Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'helix-view/src/document.rs')
| -rw-r--r-- | helix-view/src/document.rs | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index 346f04ed..885f33e8 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -934,6 +934,9 @@ impl Document { "Path is read only" )); } + + // Assume it is a hardlink to prevent data loss if the metadata cant be read (e.g. on certain Windows configurations) + let is_hardlink = helix_stdx::faccess::hardlink_count(&write_path).unwrap_or(2) > 1; let backup = if path.exists() { let path_ = write_path.clone(); // hacks: we use tempfile to handle the complex task of creating @@ -942,14 +945,22 @@ impl Document { // since the path doesn't exist yet, we just want // the path tokio::task::spawn_blocking(move || -> Option<PathBuf> { - tempfile::Builder::new() - .prefix(path_.file_name()?) - .suffix(".bck") - .make_in(path_.parent()?, |backup| std::fs::rename(&path_, backup)) - .ok()? - .into_temp_path() - .keep() - .ok() + let mut builder = tempfile::Builder::new(); + builder.prefix(path_.file_name()?).suffix(".bck"); + + let backup_path = if is_hardlink { + builder + .make_in(path_.parent()?, |backup| std::fs::copy(&path_, backup)) + .ok()? + .into_temp_path() + } else { + builder + .make_in(path_.parent()?, |backup| std::fs::rename(&path_, backup)) + .ok()? + .into_temp_path() + }; + + backup_path.keep().ok() }) .await .ok() @@ -972,7 +983,23 @@ impl Document { }; if let Some(backup) = backup { - if write_result.is_err() { + if is_hardlink { + let mut delete = true; + if write_result.is_err() { + // Restore backup + let _ = tokio::fs::copy(&backup, &write_path).await.map_err(|e| { + delete = false; + log::error!("Failed to restore backup on write failure: {e}") + }); + } + + if delete { + // Delete backup + let _ = tokio::fs::remove_file(backup) + .await + .map_err(|e| log::error!("Failed to remove backup file on write: {e}")); + } + } else if write_result.is_err() { // restore backup let _ = tokio::fs::rename(&backup, &write_path) .await |