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.rs45
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