From ac12b02437ff026bfe128c0c790ecd11cbefa2d3 Mon Sep 17 00:00:00 2001 From: Chen1Plus <122733139+Chen1Plus@users.noreply.github.com> Date: Tue, 7 Jan 2025 07:36:42 +0800 Subject: [PATCH] fix wrong error msg of `save` command on windows (#14699) fixes #14664 # Description Now, ```nu "aaa" | save -f .. ``` returns correct error message on windows. Note that the fix introduces a TOCTOU problem, which only effects the error message. It won't break any workload. # User-Facing Changes The fix won't break any workload. # Tests + Formatting I have run tests **only on windows**. # After Submitting The fix doesn't need to change documentation. --- crates/nu-command/src/filesystem/save.rs | 17 ++++++++++++++++- crates/nu-command/tests/commands/save.rs | 9 +++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/nu-command/src/filesystem/save.rs b/crates/nu-command/src/filesystem/save.rs index c4ae00f593..67fd1a2271 100644 --- a/crates/nu-command/src/filesystem/save.rs +++ b/crates/nu-command/src/filesystem/save.rs @@ -422,7 +422,22 @@ fn prepare_path( fn open_file(path: &Path, span: Span, append: bool) -> Result { let file = match (append, path.exists()) { (true, true) => std::fs::OpenOptions::new().append(true).open(path), - _ => std::fs::File::create(path), + _ => { + // This is a temporary solution until `std::fs::File::create` is fixed on Windows (rust-lang/rust#134893) + // A TOCTOU problem exists here, which may cause wrong error message to be shown + #[cfg(target_os = "windows")] + if path.is_dir() { + // It should be `io::ErrorKind::IsADirectory` but it's not available in stable yet (1.83) + Err(io::Error::new( + io::ErrorKind::Unsupported, + "Is a directory (os error 21)", + )) + } else { + std::fs::File::create(path) + } + #[cfg(not(target_os = "windows"))] + std::fs::File::create(path) + } }; file.map_err(|e| ShellError::GenericError { diff --git a/crates/nu-command/tests/commands/save.rs b/crates/nu-command/tests/commands/save.rs index 6b77160bee..8c2ea535b7 100644 --- a/crates/nu-command/tests/commands/save.rs +++ b/crates/nu-command/tests/commands/save.rs @@ -525,3 +525,12 @@ fn parent_redirection_doesnt_affect_save() { assert_eq!(actual.trim_end(), ""); }) } + +#[test] +fn force_save_to_dir() { + let actual = nu!(cwd: "crates/nu-command/tests/commands", r#" + "aaa" | save -f .. + "#); + + assert!(actual.err.contains("Is a directory")); +}