fix(windows): use rename fallback for WSL UNC

This commit is contained in:
allenxu09 committed 2026-08-07 15:34:26 +08:00
1 parent 7787b2a01d
commit cbf140d08c
1 file changed
+2 -53
+2 -53
View File
@@ -423,61 +423,10 @@ pub fn atomic_write(path: &Path, data: &[u8]) -> Result<(), AppError> {
let replace_error = std::io::Error::last_os_error();
// WSL UNC paths reject ReplaceFileW with ERROR_NOT_SUPPORTED (50).
// Fall back to rename-based replacement with a rollback backup there.
// std::fs::rename uses a different replace-existing API on Windows.
let replace_not_supported =
replace_error.raw_os_error() == Some(ERROR_NOT_SUPPORTED as i32);
if replace_not_supported {
let mut backup_name = tmp
.file_name()
.expect("temporary path must have a file name")
.to_os_string();
backup_name.push(".backup");
let backup = tmp.with_file_name(backup_name);
let backup_created = match fs::rename(path, &backup) {
Ok(()) => true,
Err(source) if source.kind() == std::io::ErrorKind::NotFound => false,
Err(source) => {
last_error = Some(source);
break;
}
};
match fs::rename(&tmp, path) {
Ok(()) => {
if backup_created {
if let Err(source) = fs::remove_file(&backup) {
log::warn!(
"Failed to remove atomic-write backup {}: {}",
backup.display(),
source
);
}
}
completed = true;
break;
}
Err(source) => {
if backup_created {
if let Err(restore_error) = fs::rename(&backup, path) {
return Err(AppError::IoContext {
context: format!(
"原子替换及回滚失败: {} -> {}; 原文件保留在 {}; 回滚错误: {}",
tmp.display(),
path.display(),
backup.display(),
restore_error
),
source,
});
}
}
last_error = Some(source);
break;
}
}
}
if replace_error.kind() != std::io::ErrorKind::NotFound {
if replace_error.kind() != std::io::ErrorKind::NotFound && !replace_not_supported {
last_error = Some(replace_error);
break;
}