fix(bash): preserved unicode in drive-alias translation

Translated the /c and /mnt/c tail per char over the valid UTF-8 suffix instead of copying raw bytes as chars, so non-ASCII path components no longer mojibake. Removed the now-unused byte separator helper and added a non-ASCII regression.

Fixes #8355
This commit is contained in:
roboomp
2026-08-12 19:26:59 +00:00
parent 87a4cd739c
commit a90dfe0dca
+18 -7
View File
@@ -84,12 +84,16 @@ fn translate_unix_drive_path(path: &Path) -> Option<PathBuf> {
let bytes = raw.as_bytes();
let (drive, tail) = drive_alias_parts(bytes)?;
// `tail` is a suffix of the valid UTF-8 `raw` beginning at an ASCII `/`
// boundary, so it is itself valid UTF-8. Translate separators per `char` —
// iterating bytes would split multibyte scalars (e.g. `José` → `José`).
let tail = std::str::from_utf8(tail).ok()?;
let mut native = String::with_capacity(3 + tail.len());
native.push(char::from(drive).to_ascii_uppercase());
native.push(':');
native.push('\\');
for &byte in tail {
native.push(if is_path_separator(byte) { '\\' } else { char::from(byte) });
for ch in tail.chars() {
native.push(if ch == '/' || ch == '\\' { '\\' } else { ch });
}
Some(PathBuf::from(native))
}
@@ -119,11 +123,6 @@ fn drive_alias_parts(bytes: &[u8]) -> Option<(u8, &[u8])> {
None
}
#[cfg(any(windows, test))]
const fn is_path_separator(byte: u8) -> bool {
byte == b'/' || byte == b'\\'
}
pub use super::platform::fs::*;
/// Extension trait for path-related filesystem operations.
@@ -189,6 +188,18 @@ mod tests {
);
}
#[test]
fn drive_alias_tail_preserves_non_ascii_components() {
assert_eq!(
translate_unix_drive_path(Path::new("/c/Users/José/file")).as_deref(),
Some(Path::new("C:\\Users\\José\\file")),
);
assert_eq!(
translate_unix_drive_path(Path::new("/mnt/d/项目/データ")).as_deref(),
Some(Path::new("D:\\项目\\データ")),
);
}
#[test]
fn pattern_drive_alias_roots_report_consumed_components() {
assert_eq!(