diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index 4d843ef63d2b..342ea9e39f9f 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -1545,6 +1545,29 @@ impl GlobalContext { // WITH an extension, which people may want to do to // support multiple Cargo versions at once and not // get a warning. + + // On Unix we can see if the two files are the same by using stat(2), + // and comparing the inode numbers. That way it doesn't matter precisely + // what spelling the link uses to refers to the other file (relative + // vs absolute pathname, etc.) Also, this is symmetrical: it doesn't mind + // which way round the symlink is. + #[cfg(unix)] + let skip_warning = if let (Ok(metadata_1), Ok(metadata_2)) = ( + fs::metadata(&possible), + fs::metadata(&possible_with_extension), + ) { + use std::os::unix::fs::MetadataExt; + let devino = |md: fs::Metadata| (md.dev(), md.ino()); + devino(metadata_1) == devino(metadata_2) + } else { + false + }; + + // Platforms other than unix don't have std::os::unix::fs::MetadataExt + // and its st_ino and st_dev methods. We can still ignore a symlink, + // but only based on its *contents*, which we must hope are identical + // to our computed pathname. + #[cfg(not(unix))] let skip_warning = if let Ok(target_path) = fs::read_link(&possible) { target_path == possible_with_extension || // allow `config` -> `config.toml`, without the parent dir(s),