diff --git a/README.md b/README.md index 6c8ea5c..ef18007 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,14 @@ Cross-platform desktop app for flashing [Arch R](https://github.com/archr-linux/ | Linux | glibc 2.31+, `webkit2gtk-4.1`, `gtk-3`, `libayatana-appindicator3` | | macOS | macOS 10.15+, Apple Silicon | +> **macOS says the app "is damaged and can't be opened".** The app is not damaged: it is not notarized with Apple (that requires a paid Apple Developer account), so Gatekeeper blocks anything downloaded from a browser. After installing, clear the quarantine flag once: +> +> ```bash +> xattr -cr "/Applications/Arch R Flasher.app" +> ``` +> +> Then open it normally. + > **Windows 7 is not supported.** Both the GUI runtime (Tauri 2 / Microsoft Edge WebView2) and the privileged flash script (PowerShell `Storage` module — `Clear-Disk`, `Get-Partition`, `Update-Disk`) require Windows 8+. Even with the bundled `bcryptprimitives.dll` shim that fixes Rust's `ProcessPrng` import, the WebView and the flash script still fail on Windows 7. Use Linux, macOS, or upgrade to Windows 10/11. ## Download diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c6b8a89..035c414 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -58,7 +58,7 @@ dependencies = [ [[package]] name = "archr-flasher" -version = "1.3.5" +version = "1.3.6" dependencies = [ "cc", "flate2", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c31a377..6c4a40d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "archr-flasher" -version = "1.3.5" +version = "1.3.6" description = "Arch R SD Card Flasher" authors = ["Arch R Linux"] edition = "2024" diff --git a/src-tauri/src/disk.rs b/src-tauri/src/disk.rs index d4e7c91..56d1f43 100644 --- a/src-tauri/src/disk.rs +++ b/src-tauri/src/disk.rs @@ -147,10 +147,13 @@ pub fn list_removable_disks() -> Vec { let mut disks = Vec::new(); - // Use plain text output (not -plist XML) to list external disks. - // Output format: "/dev/disk2 (external, physical):" as header lines. + // Enumerate every physical whole disk. `diskutil list external` alone + // misses the built-in SDXC slot on Macs (it enumerates as + // "internal, physical"), which made the picker come up empty for + // anyone using the native card reader. Removability is decided per + // disk from `diskutil info` below instead. let output = Command::new("diskutil") - .args(["list", "external"]) + .args(["list", "physical"]) .output(); let output = match output { @@ -163,15 +166,15 @@ pub fn list_removable_disks() -> Vec { for line in stdout.lines() { let line = line.trim(); - // Match lines like: "/dev/disk2 (external, physical):" - if line.starts_with("/dev/disk") && line.contains("external") { + // Header lines look like: "/dev/disk4 (external, physical):" + if line.starts_with("/dev/disk") && line.contains("physical") { if let Some(dev) = line.split_whitespace().next() { device_names.push(dev.to_string()); } } } - // Exclude boot disk (safety: never flash the system disk) + // Exclude the boot disk (safety: never flash the system disk) if let Ok(boot_info) = Command::new("diskutil").args(["info", "/"]).output() { let info_str = String::from_utf8_lossy(&boot_info.stdout); for line in info_str.lines() { @@ -186,7 +189,6 @@ pub fn list_removable_disks() -> Vec { } for device in device_names { - // Get detailed info for each disk let info_output = Command::new("diskutil") .args(["info", &device]) .output(); @@ -195,6 +197,8 @@ pub fn list_removable_disks() -> Vec { let info_str = String::from_utf8_lossy(&info.stdout); let mut size_bytes: u64 = 0; let mut name = "SD Card".to_string(); + let mut removable = false; + let mut internal = false; for info_line in info_str.lines() { if info_line.contains("Disk Size:") { @@ -210,9 +214,30 @@ pub fn list_removable_disks() -> Vec { if info_line.contains("Device / Media Name:") { name = info_line.split(':').nth(1).unwrap_or("SD Card").trim().to_string(); } + // SD cards report "Removable Media: Removable" (built-in + // reader) and/or "Ejectable: Yes" (USB readers). Fixed + // internal drives report neither. + if info_line.contains("Removable Media:") && info_line.contains("Removable") { + removable = true; + } + if info_line.contains("Ejectable:") && info_line.contains("Yes") { + removable = true; + } + if info_line.contains("Device Location:") && info_line.contains("Internal") { + internal = true; + } } - if size_bytes > 0 && size_bytes <= 128 * 1_000_000_000 { + // Internal fixed storage is only excluded when it is not + // removable media (the built-in SD slot is Internal + Removable). + if internal && !removable { + continue; + } + + // 2TB ceiling: big enough for every SDXC card (the old 128GB + // cap silently hid 256GB+ cards), small enough to keep fixed + // multi-terabyte drives out of a destructive picker. + if removable && size_bytes > 0 && size_bytes <= 2_000_000_000_000 { disks.push(DiskInfo { device, name: format!("{} ({})", name, format_size(size_bytes)), diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index ae84e39..6bd13ef 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json", "productName": "Arch R Flasher", - "version": "1.3.5", + "version": "1.3.6", "identifier": "com.archr.flasher", "build": { "frontendDist": "../src", @@ -39,7 +39,7 @@ ], "resources": [], "macOS": { - "signingIdentity": null, + "signingIdentity": "-", "entitlements": null } },