fix(bash): normalized msys paths in sed file operands

Routed sed -f script files and the in-script r/w/s///w file paths through brush-core's shell path normalizer, so /c and /mnt/c aliases open the live Windows drive instead of a phantom current-drive path. Added a Windows -f regression.

Fixes #8355
This commit is contained in:
roboomp
2026-08-12 19:34:09 +00:00
parent a90dfe0dca
commit 41684f1785
+53 -6
View File
@@ -1558,7 +1558,14 @@ pub fn compile_subst_flags(
}
let location = ScriptLocation::at_position(lines, line);
let mut path = read_file_path(lines, line)?;
if let Some(cwd) = cwd && path.is_relative() { path = cwd.join(path); }
if let Some(cwd) = cwd {
let normalized = brush_core::sys::fs::normalize_shell_path(&path);
path = if normalized.is_absolute() {
normalized.into_owned()
} else {
cwd.join(normalized)
};
}
subst.write_file = Some(NamedWriter::new(path, location)?);
return Ok(()); // 'w' is the last flag allowed
},
@@ -1633,7 +1640,12 @@ fn compile_read_file_command(
return compilation_error(lines, line, ERR_SANDBOX);
}
let mut path = read_file_path(lines, line)?;
if path.is_relative() { path = context.cwd.join(path); }
let normalized = brush_core::sys::fs::normalize_shell_path(&path);
path = if normalized.is_absolute() {
normalized.into_owned()
} else {
context.cwd.join(normalized)
};
cmd.data = CommandData::Path(path);
Ok(CommandHandling::Continue)
}
@@ -1651,7 +1663,12 @@ fn compile_write_file_command(
}
let location = ScriptLocation::at_position(lines, line);
let mut path = read_file_path(lines, line)?;
if path.is_relative() { path = context.cwd.join(path); }
let normalized = brush_core::sys::fs::normalize_shell_path(&path);
path = if normalized.is_absolute() {
normalized.into_owned()
} else {
context.cwd.join(normalized)
};
cmd.data = CommandData::NamedWriter(NamedWriter::new(path, location)?);
Ok(CommandHandling::Continue)
}
@@ -8822,9 +8839,15 @@ impl ScriptLineProvider {
line_number: 0,
};
} else {
// resolve `-f`
// script files against the shell working directory.
let resolved = if p.is_absolute() { p.clone() } else { self.cwd.join(p) };
// resolve `-f` script files against the shell working
// directory, normalizing MSYS/WSL drive aliases (`/c/...`)
// to native drive paths first — mirrors `Host::resolve`.
let normalized = brush_core::sys::fs::normalize_shell_path(p);
let resolved = if normalized.is_absolute() {
normalized.into_owned()
} else {
self.cwd.join(normalized)
};
let file = File::open(resolved)
.map_err_context(|| format!("error opening script file {}", p.quote()))?;
self.state = State::Active {
@@ -8915,6 +8938,30 @@ mod tests {
assert_eq!(lines, vec!["file line 1", "file line 2"]);
}
#[cfg(windows)]
#[test]
fn test_file_source_resolves_msys_drive_alias() {
let mut temp_file = NamedTempFile::new().unwrap();
writeln!(temp_file, "aliased line 1").unwrap();
writeln!(temp_file, "aliased line 2").unwrap();
let native = temp_file.path().to_string_lossy().replace('\\', "/");
let (drive, tail) = native
.split_once(":/")
.unwrap_or_else(|| panic!("expected drive-qualified temp path, got {native:?}"));
let alias = format!("/{}/{}", drive.to_ascii_lowercase(), tail);
let input = vec![ScriptValue::PathVal(PathBuf::from(alias))];
let mut provider = ScriptLineProvider::new(input);
let mut lines = Vec::new();
while let Some(line) = provider.next_line().unwrap() {
lines.push(line.trim_end().to_string());
}
assert_eq!(lines, vec!["aliased line 1", "aliased line 2"]);
}
#[test]
fn test_mixed_source() {
let mut temp_file = NamedTempFile::new().unwrap();