From 9c4a46bcdb7ec57c405f3bf5a3e610fca58a9838 Mon Sep 17 00:00:00 2001
From: John Smith <dyxushuai@gmail.com>
Date: Fri, 17 Mar 2023 08:20:35 +0800
Subject: [PATCH] fix: escape the space in path (#451)

---
 src-tauri/src/core/manager.rs | 36 ++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/src-tauri/src/core/manager.rs b/src-tauri/src/core/manager.rs
index 250dc5c..dfba550 100644
--- a/src-tauri/src/core/manager.rs
+++ b/src-tauri/src/core/manager.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
 /// 给clash内核的tun模式授权
 #[cfg(any(target_os = "macos", target_os = "linux"))]
 pub fn grant_permission(core: String) -> anyhow::Result<()> {
@@ -5,12 +7,15 @@ pub fn grant_permission(core: String) -> anyhow::Result<()> {
     use tauri::utils::platform::current_exe;
 
     let path = current_exe()?.with_file_name(core).canonicalize()?;
-    let path = path.display();
+    let path = path.display().to_string();
 
     log::debug!("grant_permission path: {path}");
 
     #[cfg(target_os = "macos")]
     let output = {
+        // the path of clash /Applications/Clash Verge.app/Contents/MacOS/clash
+        // https://apple.stackexchange.com/questions/82967/problem-with-empty-spaces-when-executing-shell-commands-in-applescript
+        let path = escape(&path);
         let shell = format!("chown root:admin {path}\nchmod +sx {path}");
         let command = format!(r#"do shell script "{shell}" with administrator privileges"#);
         Command::new("osascript")
@@ -35,3 +40,32 @@ pub fn grant_permission(core: String) -> anyhow::Result<()> {
         anyhow::bail!("{stderr}");
     }
 }
+
+pub fn escape<'a>(text: &'a str) -> Cow<'a, str> {
+    let bytes = text.as_bytes();
+
+    let mut owned = None;
+
+    for pos in 0..bytes.len() {
+        let special = match bytes[pos] {
+            b' ' => Some(b' '),
+            _ => None,
+        };
+        if let Some(s) = special {
+            if owned.is_none() {
+                owned = Some(bytes[0..pos].to_owned());
+            }
+            owned.as_mut().unwrap().push(b'\\');
+            owned.as_mut().unwrap().push(b'\\');
+            owned.as_mut().unwrap().push(s);
+        } else if let Some(owned) = owned.as_mut() {
+            owned.push(bytes[pos]);
+        }
+    }
+
+    if let Some(owned) = owned {
+        unsafe { Cow::Owned(String::from_utf8_unchecked(owned)) }
+    } else {
+        unsafe { Cow::Borrowed(std::str::from_utf8_unchecked(bytes)) }
+    }
+}
-- 
GitLab