@@ -6,6 +6,7 @@ use once_cell::sync::Lazy;
66
77use crate :: env:: git:: EXE_NAME ;
88
9+ mod auxiliary;
910mod git;
1011
1112/// Return the location at which installation specific git configuration file can be found, or `None`
@@ -28,84 +29,6 @@ pub fn installation_config_prefix() -> Option<&'static Path> {
2829 installation_config ( ) . map ( git:: config_to_base_path)
2930}
3031
31- /// `usr`-like directory component names that MSYS2 may provide, other than for `/usr` itself.
32- ///
33- /// These are the values of the "Prefix" column of the "Environments" and "Legacy Environments"
34- /// tables in the [MSYS2 Environments](https://www.msys2.org/docs/environments/) documentation,
35- /// with the leading `/` separator removed, except that this does not list `usr` itself.
36- ///
37- /// On Windows, we prefer to use `sh` as provided by Git for Windows, when present. To find it, we
38- /// run `git --exec-path` to get a path that is usually `<platform>/libexec/git-core` in the Git
39- /// for Windows installation, where `<platform>` is something like `mingw64`. It is also acceptable
40- /// to find `sh` in an environment not provided by Git for Windows, such as an independent MSYS2
41- /// environment in which a `git` package has been installed. However, in an unusual installation,
42- /// or if the user has set a custom value of `GIT_EXEC_PATH`, the output of `git --exec-path` may
43- /// take a form other than `<platform>/libexec/git-core`, such that finding shell at a location
44- /// like `../../../bin/sh.exe` relative to it should not be attempted. We lower the risk by
45- /// checking that `<platform>` is a plausible value that is not likely to have any other meaning.
46- ///
47- /// This involves two tradeoffs. First, it may be reasonable to find `sh.exe` in an environment
48- /// that is not MSYS2 at all, for which in principle the prefix could be different. But listing
49- /// more prefixes or matching a broad pattern of platform-like strings might be too broad. So only
50- /// prefixes that have been used in MSYS2 are considered.
51- ///
52- /// Second, we don't recognize `usr` itself here, even though is a plausible prefix. In MSYS2, it
53- /// is the prefix for MSYS2 non-native programs, i.e. those that use `msys-2.0.dll`. But unlike the
54- /// `<platform>` names we recognize, `usr` also has an effectively unbounded range of plausible
55- /// meanings on non-Unix systems, which may occasionally relate to subdirectories whose contents
56- /// are controlled by different user accounts.
57- ///
58- /// If we start with a `libexec/git-core` directory that we already use and trust, and it is in a
59- /// directory with a name like `mingw64`, we infer that this `mingw64` directory has the expected
60- /// meaning and that its `usr` sibling, if present, is acceptable to treat as though it is a
61- /// first-level directory inside an MSYS2-like tree. So we are willing to traverse down to
62- /// `usr/sh.exe` and attempt to use it. But if the `libexec/git-core` we use and trust is inside a
63- /// directory named `usr`, that `usr` directory may still not have the meaning we expect of `usr`.
64- ///
65- /// The conditions for a privilege escalation attack or other serious malfunction seem unlikely. If
66- /// research indicates the risk is low enough, `usr` may be added. But for now it is omitted.
67- const MSYS_USR_VARIANTS : & [ & str ] = & [ "mingw64" , "mingw32" , "clangarm64" , "clang64" , "clang32" , "ucrt64" ] ;
68-
69- /// Shell path fragments to concatenate to the root of a Git for Windows or MSYS2 installation.
70- ///
71- /// These look like absolute Unix-style paths, but the leading `/` separators are present because
72- /// they simplify forming paths like `C:/Program Files/Git` obtained by removing trailing
73- /// components from the output of `git --exec-path`.
74- const RAW_SH_EXE_PATH_SUFFIXES : & [ & str ] = & [
75- "/bin/sh.exe" , // Usually a shim, which currently we prefer, if available.
76- "/usr/bin/sh.exe" ,
77- ] ;
78-
79- ///
80- fn raw_join ( path : & Path , raw_suffix : & str ) -> OsString {
81- let mut raw_path = OsString :: from ( path) ;
82- raw_path. push ( raw_suffix) ;
83- raw_path
84- }
85-
86- ///
87- fn find_sh_on_windows ( ) -> Option < OsString > {
88- core_dir ( )
89- . filter ( |core| core. is_absolute ( ) && core. ends_with ( "libexec/git-core" ) )
90- . and_then ( |core| core. ancestors ( ) . nth ( 2 ) )
91- . filter ( |prefix| {
92- // Only use `libexec/git-core` from inside something `usr`-like, such as `mingw64`.
93- MSYS_USR_VARIANTS . iter ( ) . any ( |name| prefix. ends_with ( name) )
94- } )
95- . and_then ( |prefix| prefix. parent ( ) )
96- . into_iter ( )
97- . flat_map ( |git_root| {
98- // Enumerate locations where `sh.exe` usually is. To avoid breaking scripts that assume the
99- // shell's own path contains no `\`, and so messages are more readable, append literally
100- // with `/` separators. The path from `git --exec-path` already uses `/` separators (and no
101- // trailing `/`) unless explicitly overridden to an unusual value via `GIT_EXEC_PATH`.
102- RAW_SH_EXE_PATH_SUFFIXES
103- . iter ( )
104- . map ( |raw_suffix| raw_join ( git_root, raw_suffix) )
105- } )
106- . find ( |raw_path| Path :: new ( raw_path) . is_file ( ) )
107- }
108-
10932/// Return the shell that Git would use, the shell to execute commands from.
11033///
11134/// On Windows, this is the full path to `sh.exe` bundled with Git for Windows if we can find it.
@@ -117,7 +40,7 @@ fn find_sh_on_windows() -> Option<OsString> {
11740pub fn shell ( ) -> & ' static OsStr {
11841 static PATH : Lazy < OsString > = Lazy :: new ( || {
11942 if cfg ! ( windows) {
120- find_sh_on_windows ( ) . unwrap_or_else ( || "sh.exe" . into ( ) )
43+ auxiliary :: find_sh_on_windows ( ) . unwrap_or_else ( || "sh.exe" . into ( ) )
12144 } else {
12245 "/bin/sh" . into ( )
12346 }
0 commit comments