mirror of
https://github.com/rust-lang/cargo.git
synced 2025-09-25 11:14:46 +00:00
Auto merge of #11866 - Zoxc:fs-non-canon, r=ehuss
Add `try_canonicalize` and use it over `std::fs::canonicalize` This adds a `try_canonicalize` function that calls `std::fs::canonicalize` and on Windows falls back to getting an absolute path. Uses of `canonicalize` have been replaced with `std::fs::canonicalize`. On Windows `std::fs::canonicalize` may fail due to incomplete drivers. In particular `ImDisk` does not support it. Combined with https://github.com/rust-lang/rust/pull/109231 this allows compiling crates on an `ImDisk` RAM disk and I've tested that it works with various configuration using [rcb](https://github.com/Zoxc/rcb).
This commit is contained in:
commit
1b2de2169b
@ -3,7 +3,7 @@
|
||||
use crate::core::Target;
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::interning::InternedString;
|
||||
use crate::util::{Config, StableHasher};
|
||||
use crate::util::{try_canonicalize, Config, StableHasher};
|
||||
use anyhow::Context as _;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeSet;
|
||||
@ -138,8 +138,7 @@ impl CompileTarget {
|
||||
// If `name` ends in `.json` then it's likely a custom target
|
||||
// specification. Canonicalize the path to ensure that different builds
|
||||
// with different paths always produce the same result.
|
||||
let path = Path::new(name)
|
||||
.canonicalize()
|
||||
let path = try_canonicalize(Path::new(name))
|
||||
.with_context(|| format!("target path {:?} is not a valid file", name))?;
|
||||
|
||||
let name = path
|
||||
|
@ -367,9 +367,9 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::core::compiler::unit_graph::UnitDep;
|
||||
use crate::core::Package;
|
||||
use crate::util;
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::interning::InternedString;
|
||||
use crate::util::{self, try_canonicalize};
|
||||
use crate::util::{internal, path_args, profile, StableHasher};
|
||||
use crate::{Config, CARGO_ENV};
|
||||
|
||||
@ -1951,8 +1951,8 @@ pub fn translate_dep_info(
|
||||
) -> CargoResult<()> {
|
||||
let depinfo = parse_rustc_dep_info(rustc_dep_info)?;
|
||||
|
||||
let target_root = target_root.canonicalize()?;
|
||||
let pkg_root = pkg_root.canonicalize()?;
|
||||
let target_root = try_canonicalize(target_root)?;
|
||||
let pkg_root = try_canonicalize(pkg_root)?;
|
||||
let mut on_disk_info = EncodedDepInfo::default();
|
||||
on_disk_info.env = depinfo.env;
|
||||
|
||||
@ -1995,7 +1995,7 @@ pub fn translate_dep_info(
|
||||
// If canonicalization fails, just use the abs path. There is currently
|
||||
// a bug where --remap-path-prefix is affecting .d files, causing them
|
||||
// to point to non-existent paths.
|
||||
let canon_file = abs_file.canonicalize().unwrap_or_else(|_| abs_file.clone());
|
||||
let canon_file = try_canonicalize(&abs_file).unwrap_or_else(|_| abs_file.clone());
|
||||
|
||||
let (ty, path) = if let Ok(stripped) = canon_file.strip_prefix(&target_root) {
|
||||
(DepInfoPathType::TargetRootRelative, stripped)
|
||||
|
@ -4,7 +4,7 @@ use crate::core::{GitReference, Package, Workspace};
|
||||
use crate::ops;
|
||||
use crate::sources::path::PathSource;
|
||||
use crate::sources::CRATES_IO_REGISTRY;
|
||||
use crate::util::{CargoResult, Config};
|
||||
use crate::util::{try_canonicalize, CargoResult, Config};
|
||||
use anyhow::{bail, Context as _};
|
||||
use cargo_util::{paths, Sha256};
|
||||
use serde::Serialize;
|
||||
@ -83,7 +83,7 @@ fn sync(
|
||||
workspaces: &[&Workspace<'_>],
|
||||
opts: &VendorOptions<'_>,
|
||||
) -> CargoResult<VendorConfig> {
|
||||
let canonical_destination = opts.destination.canonicalize();
|
||||
let canonical_destination = try_canonicalize(opts.destination);
|
||||
let canonical_destination = canonical_destination.as_deref().unwrap_or(opts.destination);
|
||||
let dest_dir_already_exists = canonical_destination.exists();
|
||||
|
||||
@ -125,7 +125,7 @@ fn sync(
|
||||
// Don't delete actual source code!
|
||||
if pkg.source_id().is_path() {
|
||||
if let Ok(path) = pkg.source_id().url().to_file_path() {
|
||||
if let Ok(path) = path.canonicalize() {
|
||||
if let Ok(path) = try_canonicalize(path) {
|
||||
to_remove.remove(&path);
|
||||
}
|
||||
}
|
||||
|
@ -72,9 +72,9 @@ use crate::core::{features, CliUnstable, Shell, SourceId, Workspace, WorkspaceRo
|
||||
use crate::ops::{self, RegistryCredentialConfig};
|
||||
use crate::util::auth::Secret;
|
||||
use crate::util::errors::CargoResult;
|
||||
use crate::util::validate_package_name;
|
||||
use crate::util::CanonicalUrl;
|
||||
use crate::util::{internal, toml as cargo_toml};
|
||||
use crate::util::{try_canonicalize, validate_package_name};
|
||||
use crate::util::{FileLock, Filesystem, IntoUrl, IntoUrlWithBase, Rustc};
|
||||
use anyhow::{anyhow, bail, format_err, Context as _};
|
||||
use cargo_util::paths;
|
||||
@ -433,11 +433,11 @@ impl Config {
|
||||
// commands that use Cargo as a library to inherit (via `cargo <subcommand>`)
|
||||
// or set (by setting `$CARGO`) a correct path to `cargo` when the current exe
|
||||
// is not actually cargo (e.g., `cargo-*` binaries, Valgrind, `ld.so`, etc.).
|
||||
let exe = self
|
||||
.get_env_os(crate::CARGO_ENV)
|
||||
.map(PathBuf::from)
|
||||
.ok_or_else(|| anyhow!("$CARGO not set"))?
|
||||
.canonicalize()?;
|
||||
let exe = try_canonicalize(
|
||||
self.get_env_os(crate::CARGO_ENV)
|
||||
.map(PathBuf::from)
|
||||
.ok_or_else(|| anyhow!("$CARGO not set"))?,
|
||||
)?;
|
||||
Ok(exe)
|
||||
};
|
||||
|
||||
@ -446,7 +446,7 @@ impl Config {
|
||||
// The method varies per operating system and might fail; in particular,
|
||||
// it depends on `/proc` being mounted on Linux, and some environments
|
||||
// (like containers or chroots) may not have that available.
|
||||
let exe = env::current_exe()?.canonicalize()?;
|
||||
let exe = try_canonicalize(env::current_exe()?)?;
|
||||
Ok(exe)
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
pub use self::canonical_url::CanonicalUrl;
|
||||
@ -133,6 +134,79 @@ pub fn truncate_with_ellipsis(s: &str, max_width: usize) -> String {
|
||||
prefix
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[inline]
|
||||
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
|
||||
std::fs::canonicalize(&path)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[inline]
|
||||
pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> {
|
||||
use std::ffi::OsString;
|
||||
use std::io::Error;
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::{io::ErrorKind, ptr};
|
||||
use windows_sys::Win32::Foundation::{GetLastError, SetLastError};
|
||||
use windows_sys::Win32::Storage::FileSystem::GetFullPathNameW;
|
||||
|
||||
// On Windows `canonicalize` may fail, so we fall back to getting an absolute path.
|
||||
std::fs::canonicalize(&path).or_else(|_| {
|
||||
// Return an error if a file does not exist for better compatiblity with `canonicalize`
|
||||
if !path.as_ref().try_exists()? {
|
||||
return Err(Error::new(ErrorKind::NotFound, "the path was not found"));
|
||||
}
|
||||
|
||||
// This code is based on the unstable `std::path::absolute` and could be replaced with it
|
||||
// if it's stabilized.
|
||||
|
||||
let path = path.as_ref().as_os_str();
|
||||
let mut path_u16 = Vec::with_capacity(path.len() + 1);
|
||||
path_u16.extend(path.encode_wide());
|
||||
if path_u16.iter().find(|c| **c == 0).is_some() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidInput,
|
||||
"strings passed to WinAPI cannot contain NULs",
|
||||
));
|
||||
}
|
||||
path_u16.push(0);
|
||||
|
||||
loop {
|
||||
unsafe {
|
||||
SetLastError(0);
|
||||
let len =
|
||||
GetFullPathNameW(path_u16.as_ptr(), 0, &mut [] as *mut u16, ptr::null_mut());
|
||||
if len == 0 {
|
||||
let error = GetLastError();
|
||||
if error != 0 {
|
||||
return Err(Error::from_raw_os_error(error as i32));
|
||||
}
|
||||
}
|
||||
let mut result = vec![0u16; len as usize];
|
||||
|
||||
let write_len = GetFullPathNameW(
|
||||
path_u16.as_ptr(),
|
||||
result.len().try_into().unwrap(),
|
||||
result.as_mut_ptr().cast::<u16>(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
if write_len == 0 {
|
||||
let error = GetLastError();
|
||||
if error != 0 {
|
||||
return Err(Error::from_raw_os_error(error as i32));
|
||||
}
|
||||
}
|
||||
|
||||
if write_len <= len {
|
||||
return Ok(PathBuf::from(OsString::from_wide(
|
||||
&result[0..(write_len as usize)],
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
Loading…
x
Reference in New Issue
Block a user