]>
Commit | Line | Data |
---|---|---|
d9579d0f AL |
1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use std::path::{self, Path, PathBuf}; | |
12 | use std::ffi::OsString; | |
5bcae85e SL |
13 | use std::fs; |
14 | use std::io; | |
d9579d0f | 15 | |
62682a34 SL |
16 | // Unfortunately, on windows, it looks like msvcrt.dll is silently translating |
17 | // verbatim paths under the hood to non-verbatim paths! This manifests itself as | |
18 | // gcc looking like it cannot accept paths of the form `\\?\C:\...`, but the | |
19 | // real bug seems to lie in msvcrt.dll. | |
20 | // | |
21 | // Verbatim paths are generally pretty rare, but the implementation of | |
22 | // `fs::canonicalize` currently generates paths of this form, meaning that we're | |
23 | // going to be passing quite a few of these down to gcc, so we need to deal with | |
24 | // this case. | |
d9579d0f AL |
25 | // |
26 | // For now we just strip the "verbatim prefix" of `\\?\` from the path. This | |
27 | // will probably lose information in some cases, but there's not a whole lot | |
62682a34 SL |
28 | // more we can do with a buggy msvcrt... |
29 | // | |
30 | // For some more information, see this comment: | |
31 | // https://github.com/rust-lang/rust/issues/25505#issuecomment-102876737 | |
d9579d0f AL |
32 | pub fn fix_windows_verbatim_for_gcc(p: &Path) -> PathBuf { |
33 | if !cfg!(windows) { | |
34 | return p.to_path_buf() | |
35 | } | |
36 | let mut components = p.components(); | |
37 | let prefix = match components.next() { | |
38 | Some(path::Component::Prefix(p)) => p, | |
39 | _ => return p.to_path_buf(), | |
40 | }; | |
62682a34 SL |
41 | match prefix.kind() { |
42 | path::Prefix::VerbatimDisk(disk) => { | |
43 | let mut base = OsString::from(format!("{}:", disk as char)); | |
44 | base.push(components.as_path()); | |
45 | PathBuf::from(base) | |
46 | } | |
47 | path::Prefix::VerbatimUNC(server, share) => { | |
48 | let mut base = OsString::from(r"\\"); | |
49 | base.push(server); | |
50 | base.push(r"\"); | |
51 | base.push(share); | |
52 | base.push(components.as_path()); | |
53 | PathBuf::from(base) | |
54 | } | |
55 | _ => p.to_path_buf(), | |
56 | } | |
d9579d0f | 57 | } |
5bcae85e SL |
58 | |
59 | /// Copy `p` into `q`, preferring to use hard-linking if possible. If | |
60 | /// `q` already exists, it is removed first. | |
61 | pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<()> { | |
62 | let p = p.as_ref(); | |
63 | let q = q.as_ref(); | |
64 | if q.exists() { | |
65 | try!(fs::remove_file(&q)); | |
66 | } | |
67 | fs::hard_link(p, q) | |
68 | .or_else(|_| fs::copy(p, q).map(|_| ())) | |
69 | } |