Use getmntinfo(3) to list mounted volumes

Max Brunsfeld and Nathan Sobo created

Co-Authored-By: Nathan Sobo <nathan@zed.dev>

Change summary

Cargo.lock          |  2 --
zed/Cargo.toml      |  4 ----
zed/src/worktree.rs | 39 +++++++++++++++------------------------
3 files changed, 15 insertions(+), 30 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -2220,7 +2220,6 @@ version = "0.1.0"
 dependencies = [
  "anyhow",
  "arrayvec",
- "cocoa",
  "crossbeam-channel",
  "ctor",
  "dirs",
@@ -2234,7 +2233,6 @@ dependencies = [
  "libc",
  "log",
  "num_cpus",
- "objc",
  "parking_lot",
  "postage",
  "rand 0.8.3",

zed/Cargo.toml 🔗

@@ -42,7 +42,3 @@ env_logger = "0.8"
 serde_json = {version = "1.0.64", features = ["preserve_order"]}
 tempdir = "0.3.7"
 unindent = "0.1.7"
-
-[target.'cfg(target_os = "macos")'.dependencies]
-cocoa = "0.24"
-objc = "0.2"

zed/src/worktree.rs 🔗

@@ -18,13 +18,13 @@ use postage::{
 use smol::{channel::Sender, Timer};
 use std::{
     collections::{BTreeMap, HashMap, HashSet},
-    ffi::OsStr,
+    ffi::{CStr, OsStr},
     fmt, fs,
     future::Future,
     io::{self, Read, Write},
     mem,
     ops::{AddAssign, Deref},
-    os::unix::fs::MetadataExt,
+    os::unix::{ffi::OsStrExt, fs::MetadataExt},
     path::{Path, PathBuf},
     sync::Arc,
     time::Duration,
@@ -1229,30 +1229,21 @@ impl<'a> Iterator for FileIter<'a> {
 }
 
 fn mounted_volume_paths() -> Vec<PathBuf> {
-    use cocoa::{
-        base::{id, nil},
-        foundation::{NSArray, NSString, NSURL},
-    };
-    use objc::{class, msg_send, sel, sel_impl};
-
     unsafe {
-        let manager: id = msg_send![class!(NSFileManager), defaultManager];
-        let array = NSArray::array(nil);
-        let urls: id =
-            msg_send![manager, mountedVolumeURLsIncludingResourceValuesForKeys:array options:0];
-        let len = urls.count() as usize;
-        let mut result = Vec::with_capacity(len);
-        for i in 0..len {
-            let url = urls.objectAtIndex(i as u64);
-            let string = url.absoluteString();
-            let string = std::ffi::CStr::from_ptr(string.UTF8String())
-                .to_string_lossy()
-                .to_string();
-            if let Some(path) = string.strip_prefix("file://") {
-                result.push(PathBuf::from(path));
+        let mut stat_ptr: *mut libc::statfs = std::ptr::null_mut();
+        let count = libc::getmntinfo(&mut stat_ptr as *mut _, libc::MNT_WAIT);
+        if count >= 0 {
+            std::slice::from_raw_parts(stat_ptr, count as usize)
+                .iter()
+                .map(|stat| {
+                    PathBuf::from(OsStr::from_bytes(
+                        CStr::from_ptr(&stat.f_mntonname[0]).to_bytes(),
+                    ))
+                })
+                .collect()
+        } else {
+            panic!("failed to run getmntinfo");
             }
-        }
-        result
     }
 }