Canonicalize settings to avoid overwriting symlinks (#7632)

Matt Bond created

Release Notes:

- Fixed theme selector overwriting settings file symlinks
([#4469](https://github.com/zed-industries/zed/issues/4469)).

Change summary

crates/settings/src/settings_file.rs | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)

Detailed changes

crates/settings/src/settings_file.rs 🔗

@@ -1,9 +1,9 @@
 use crate::{settings_store::SettingsStore, Settings};
-use anyhow::Result;
+use anyhow::{Context, Result};
 use fs::Fs;
 use futures::{channel::mpsc, StreamExt};
 use gpui::{AppContext, BackgroundExecutor};
-use std::{io::ErrorKind, path::PathBuf, str, sync::Arc, time::Duration};
+use std::{io::ErrorKind, path::PathBuf, sync::Arc, time::Duration};
 use util::{paths, ResultExt};
 
 pub const EMPTY_THEME_NAME: &'static str = "empty-theme";
@@ -115,7 +115,14 @@ pub fn update_settings_file<T: Settings>(
         let new_text = cx.read_global(|store: &SettingsStore, _cx| {
             store.new_text_for_update::<T>(old_text, update)
         })?;
-        fs.atomic_write(paths::SETTINGS.clone(), new_text).await?;
+        let initial_path = paths::SETTINGS.as_path();
+        let resolved_path = fs
+            .canonicalize(initial_path)
+            .await
+            .with_context(|| format!("Failed to canonicalize settings path {:?}", initial_path))?;
+        fs.atomic_write(resolved_path.clone(), new_text)
+            .await
+            .with_context(|| format!("Failed to write settings to file {:?}", resolved_path))?;
         anyhow::Ok(())
     })
     .detach_and_log_err(cx);