diff --git a/src/cargo/ops/cargo_package.rs b/src/cargo/ops/cargo_package.rs index 772c6f87f67..5dcdd2ff4ed 100644 --- a/src/cargo/ops/cargo_package.rs +++ b/src/cargo/ops/cargo_package.rs @@ -823,25 +823,12 @@ fn check_filename(file: &Path, shell: &mut Shell) -> CargoResult<()> { file.display() ) } - let mut check_windows = |name| -> CargoResult<()> { - if restricted_names::is_windows_reserved(name) { - shell.warn(format!( - "file {} is a reserved Windows filename, \ + if restricted_names::is_windows_reserved_path(file) { + shell.warn(format!( + "file {} is a reserved Windows filename, \ it will not work on Windows platforms", - file.display() - ))?; - } - Ok(()) - }; - for component in file.iter() { - if let Some(component) = component.to_str() { - check_windows(component)?; - } - } - if file.extension().is_some() { - if let Some(stem) = file.file_stem().and_then(|s| s.to_str()) { - check_windows(stem)?; - } + file.display() + ))?; } Ok(()) } diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index 9a181b9077f..4c340026cbf 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -178,7 +178,7 @@ use crate::sources::PathSource; use crate::util::errors::CargoResultExt; use crate::util::hex; use crate::util::into_url::IntoUrl; -use crate::util::{CargoResult, Config, Filesystem}; +use crate::util::{restricted_names, CargoResult, Config, Filesystem}; const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok"; pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index"; @@ -495,11 +495,18 @@ impl<'cfg> RegistrySource<'cfg> { prefix ) } - - // Once that's verified, unpack the entry as usual. - entry - .unpack_in(parent) - .chain_err(|| format!("failed to unpack entry at `{}`", entry_path.display()))?; + // Unpacking failed + let mut result = entry.unpack_in(parent).map_err(anyhow::Error::from); + if cfg!(windows) && restricted_names::is_windows_reserved_path(&entry_path) { + result = result.chain_err(|| { + format!( + "`{}` appears to contain a reserved Windows path, \ + it cannot be extracted on Windows", + entry_path.display() + ) + }); + } + result.chain_err(|| format!("failed to unpack entry at `{}`", entry_path.display()))?; } // Write to the lock file to indicate that unpacking was successful. diff --git a/src/cargo/util/restricted_names.rs b/src/cargo/util/restricted_names.rs index ad9df7dc122..3e1cb036de8 100644 --- a/src/cargo/util/restricted_names.rs +++ b/src/cargo/util/restricted_names.rs @@ -2,6 +2,7 @@ use crate::util::CargoResult; use anyhow::bail; +use std::path::Path; /// Returns `true` if the name contains non-ASCII characters. pub fn is_non_ascii_name(name: &str) -> bool { @@ -81,3 +82,13 @@ pub fn validate_package_name(name: &str, what: &str, help: &str) -> CargoResult< } Ok(()) } + +// Check the entire path for names reserved in Windows. +pub fn is_windows_reserved_path(path: &Path) -> bool { + path.iter() + .filter_map(|component| component.to_str()) + .any(|component| { + let stem = component.split('.').next().unwrap(); + is_windows_reserved(stem) + }) +} diff --git a/tests/testsuite/package.rs b/tests/testsuite/package.rs index ddfeea58d9f..c04b7786d46 100644 --- a/tests/testsuite/package.rs +++ b/tests/testsuite/package.rs @@ -1744,3 +1744,55 @@ src/lib.rs ) .run(); } + +#[cargo_test] +#[cfg(windows)] +fn reserved_windows_name() { + Package::new("bar", "1.0.0") + .file("src/lib.rs", "pub mod aux;") + .file("src/aux.rs", "") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.0.1" + authors = [] + license = "MIT" + description = "foo" + + [dependencies] + bar = "1.0.0" + "#, + ) + .file("src/main.rs", "extern crate bar;\nfn main() { }") + .build(); + p.cargo("package") + .with_status(101) + .with_stderr_contains( + "\ +error: failed to verify package tarball + +Caused by: + failed to download replaced source registry `[..]` + +Caused by: + failed to unpack package `[..] `[..]`)` + +Caused by: + failed to unpack entry at `[..]aux.rs` + +Caused by: + `[..]aux.rs` appears to contain a reserved Windows path, it cannot be extracted on Windows + +Caused by: + failed to unpack `[..]aux.rs` + +Caused by: + failed to unpack `[..]aux.rs` into `[..]aux.rs`", + ) + .run(); +}