You've already forked archr-flasher
mirror of
https://github.com/archr-linux/archr-flasher.git
synced 2026-07-12 18:19:47 -07:00
flasher: find SD cards in the built-in Mac reader, ease Gatekeeper
macOS disk discovery only asked diskutil for external disks, but the built-in SDXC slot on Macs enumerates as internal, so the picker came up empty for anyone using the native reader. Enumerate every physical whole disk and decide per disk from Removable Media / Ejectable instead, still excluding the boot disk and fixed internal drives, and raise the size ceiling that silently hid 256GB+ cards to 2TB. Sign the macOS bundles with the ad-hoc identity (Apple Silicon kills completely unsigned binaries with the misleading damaged-app dialog) and document the one-time xattr quarantine clear in the README, since proper notarization needs a paid Apple Developer account. Bump to 1.3.6.
This commit is contained in:
@@ -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
|
||||
|
||||
Generated
+1
-1
@@ -58,7 +58,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "archr-flasher"
|
||||
version = "1.3.5"
|
||||
version = "1.3.6"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"flate2",
|
||||
|
||||
@@ -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"
|
||||
|
||||
+33
-8
@@ -147,10 +147,13 @@ pub fn list_removable_disks() -> Vec<DiskInfo> {
|
||||
|
||||
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<DiskInfo> {
|
||||
|
||||
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<DiskInfo> {
|
||||
}
|
||||
|
||||
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<DiskInfo> {
|
||||
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<DiskInfo> {
|
||||
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)),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user