diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /compiler/rustc_fs_util/src | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_fs_util/src/lib.rs | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs new file mode 100644 index 000000000..87e97c746 --- /dev/null +++ b/compiler/rustc_fs_util/src/lib.rs @@ -0,0 +1,90 @@ +use std::ffi::CString; +use std::fs; +use std::io; +use std::path::{Path, PathBuf}; + +// Unfortunately, on windows, it looks like msvcrt.dll is silently translating +// verbatim paths under the hood to non-verbatim paths! This manifests itself as +// gcc looking like it cannot accept paths of the form `\\?\C:\...`, but the +// real bug seems to lie in msvcrt.dll. +// +// Verbatim paths are generally pretty rare, but the implementation of +// `fs::canonicalize` currently generates paths of this form, meaning that we're +// going to be passing quite a few of these down to gcc, so we need to deal with +// this case. +// +// For now we just strip the "verbatim prefix" of `\\?\` from the path. This +// will probably lose information in some cases, but there's not a whole lot +// more we can do with a buggy msvcrt... +// +// For some more information, see this comment: +// https://github.com/rust-lang/rust/issues/25505#issuecomment-102876737 +#[cfg(windows)] +pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { + use std::ffi::OsString; + use std::path; + let mut components = p.components(); + let prefix = match components.next() { + Some(path::Component::Prefix(p)) => p, + _ => return p.to_path_buf(), + }; + match prefix.kind() { + path::Prefix::VerbatimDisk(disk) => { + let mut base = OsString::from(format!("{}:", disk as char)); + base.push(components.as_path()); + PathBuf::from(base) + } + path::Prefix::VerbatimUNC(server, share) => { + let mut base = OsString::from(r"\\"); + base.push(server); + base.push(r"\"); + base.push(share); + base.push(components.as_path()); + PathBuf::from(base) + } + _ => p.to_path_buf(), + } +} + +#[cfg(not(windows))] +pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { + p.to_path_buf() +} + +pub enum LinkOrCopy { + Link, + Copy, +} + +/// Copies `p` into `q`, preferring to use hard-linking if possible. If +/// `q` already exists, it is removed first. +/// The result indicates which of the two operations has been performed. +pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<LinkOrCopy> { + let p = p.as_ref(); + let q = q.as_ref(); + match fs::remove_file(&q) { + Ok(()) => (), + Err(err) if err.kind() == io::ErrorKind::NotFound => (), + Err(err) => return Err(err), + } + + match fs::hard_link(p, q) { + Ok(()) => Ok(LinkOrCopy::Link), + Err(_) => match fs::copy(p, q) { + Ok(_) => Ok(LinkOrCopy::Copy), + Err(e) => Err(e), + }, + } +} + +#[cfg(unix)] +pub fn path_to_c_string(p: &Path) -> CString { + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + let p: &OsStr = p.as_ref(); + CString::new(p.as_bytes()).unwrap() +} +#[cfg(windows)] +pub fn path_to_c_string(p: &Path) -> CString { + CString::new(p.to_str().unwrap()).unwrap() +} |