diff --git a/Cargo.lock b/Cargo.lock
index 14aae8f..9210fa7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1158,8 +1158,6 @@ dependencies = [
 [[package]]
 name = "eframe"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0d49426c3e72a6728b0c790d22db8bf7bbcff10d83b8b6f3a01295be982302e"
 dependencies = [
  "bytemuck",
  "egui",
@@ -1180,8 +1178,6 @@ dependencies = [
 [[package]]
 name = "egui"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc9fcd393c3daaaf5909008a1d948319d538b79c51871e4df0993260260a94e4"
 dependencies = [
  "ahash 0.8.0",
  "epaint",
@@ -1192,8 +1188,6 @@ dependencies = [
 [[package]]
 name = "egui-winit"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07ddc525334c416e11580123e147b970f738507f427c9fb1cd09ea2dd7416a3a"
 dependencies = [
  "arboard",
  "egui",
@@ -1207,8 +1201,6 @@ dependencies = [
 [[package]]
 name = "egui_extras"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f698f685bb0ad39e87109e2f695ded0bccde77d5d40bbf7590cb5561c1e3039d"
 dependencies = [
  "egui",
  "image",
@@ -1217,8 +1209,6 @@ dependencies = [
 [[package]]
 name = "egui_glow"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad77d4a00402bae9658ee64be148f4b2a0b38e4fc7874970575ca01ed1c5b75d"
 dependencies = [
  "bytemuck",
  "egui",
@@ -1238,8 +1228,6 @@ checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
 [[package]]
 name = "emath"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9542a40106fdba943a055f418d1746a050e1a903a049b030c2b097d4686a33cf"
 dependencies = [
  "bytemuck",
 ]
@@ -1296,8 +1284,6 @@ dependencies = [
 [[package]]
 name = "epaint"
 version = "0.19.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ba04741be7f6602b1a1b28f1082cce45948a7032961c52814f8946b28493300"
 dependencies = [
  "ab_glyph",
  "ahash 0.8.0",
@@ -1809,7 +1795,6 @@ dependencies = [
  "reqwest",
  "rusqlite",
  "serde",
- "serde_derive",
  "serde_json",
  "sha2 0.10.6",
  "tar",
diff --git a/Cargo.toml b/Cargo.toml
index a16b273..e5fa50a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,17 +10,17 @@ arti-hyper = "0.7.0"
 bytes = "1.2.1"
 chrono = "0.4.22"
 dirs = "4.0.0"
-eframe = "0.19.0"
-egui = "0.19.0"
-egui_extras = { version = "0.19.0", features = ["image"] }
+#eframe = "0.19.0"
+#egui = "0.19.0"
+#egui_extras = { version = "0.19.0", features = ["image"] }
 ## [external/egui/crates/eframe/src/native/run.rs] line 41: [.with_srgb(true)]
 ## This line causes a [panic!] inside a Windows VM, from a Linux host.
 ## There are many issue threads and PRs to fix it but for now,
 ## this is here for convenience sake when I'm testing.
 ## The only change is [.with_srgb()] is set to [false].
-#eframe = { path = "external/egui/crates/eframe" }
-#egui = { path = "external/egui/crates/egui" }
-#egui_extras = { path = "external/egui/crates/egui_extras", features = ["image"] }
+eframe = { path = "external/egui/crates/eframe" }
+egui = { path = "external/egui/crates/egui" }
+egui_extras = { path = "external/egui/crates/egui_extras", features = ["image"] }
 env_logger = "0.9.1"
 figment = { version = "0.10.8", features = ["toml"] }
 flate2 = "1.0"
@@ -37,24 +37,29 @@ rand = "0.8.5"
 regex = "1.6.0"
 reqwest = { version = "0.11.12", features = ["blocking", "json"] }
 rusqlite = { version = "0.28.0", features = ["bundled"] }
-serde = "1.0.145"
-serde_derive = "1.0.145"
+serde = { version = "1.0.145", features = ["rc", "derive"] }
 serde_json = "1.0"
 sha2 = "0.10.6"
-tar = "0.4.38"
 tls-api = "0.9.0"
 tls-api-native-tls = "0.9.0"
 tokio = { version = "1.21.2", features = ["full"] }
 toml = "0.5.9"
 tor-rtcompat = "0.7.0"
 walkdir = "2.3.2"
+
+# Unix dependencies
+[target.'cfg(unix)'.dependencies]
+tar = "0.4.38"
+
+# Windows dependencies
+[target.'cfg(windows)'.dependencies]
 zip = "0.6.3"
 
-# For Windows
+# For Windows build (icon)
 [target.'cfg(windows)'.build-dependencies]
 winres = "0.1.12"
 
-# For macOS (cargo-bundle)
+# For macOS build (cargo-bundle)
 [package.metadata.bundle]
 identifier = "io.github.hinto-janaiyo.gupax"
 icon = ["images/png/icon@2x.png"]
diff --git a/src/gupax.rs b/src/gupax.rs
index a1cf49a..8c92d29 100644
--- a/src/gupax.rs
+++ b/src/gupax.rs
@@ -16,7 +16,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 use std::path::Path;
-use crate::App;
+use crate::{App,State};
 use egui::WidgetType::Button;
 use crate::constants::*;
 use crate::state::{Gupax,Version};
@@ -26,7 +26,7 @@ use std::sync::{Arc,Mutex};
 use log::*;
 
 impl Gupax {
-	pub fn show(state: &mut Gupax, og: &Gupax, width: f32, height: f32, update: &mut Update, version: Version, ctx: &egui::Context, ui: &mut egui::Ui) {
+	pub fn show(state: &mut Gupax, og: &Arc<Mutex<State>>, state_ver: &Arc<Mutex<Version>>, update: &Arc<Mutex<Update>>, width: f32, height: f32, ctx: &egui::Context, ui: &mut egui::Ui) {
 		// Update button + Progress bar
 		ui.group(|ui| {
 				// These are in unnecessary [ui.vertical()]'s
@@ -35,30 +35,44 @@ impl Gupax {
 				// I have to pick one. This one seperates them though.
 				let height = height/6.0;
 				let width = width - SPACE;
-				let updating = *update.updating.lock().unwrap();
+				let updating = *update.lock().unwrap().updating.lock().unwrap();
 				ui.vertical(|ui| {
 					ui.set_enabled(!updating);
 					if ui.add_sized([width, height], egui::Button::new("Check for updates")).on_hover_text(GUPAX_UPDATE).clicked() {
-						update.path_p2pool = og.absolute_p2pool_path.display().to_string();
-						update.path_xmrig = og.absolute_xmrig_path.display().to_string();
-						update.tor = og.update_via_tor;
-						let update = Arc::new(Mutex::new(update.clone()));
+						update.lock().unwrap().path_p2pool = og.lock().unwrap().gupax.absolute_p2pool_path.display().to_string();
+						update.lock().unwrap().path_xmrig = og.lock().unwrap().gupax.absolute_xmrig_path.display().to_string();
+						update.lock().unwrap().tor = og.lock().unwrap().gupax.update_via_tor;
+						let og = Arc::clone(&og);
+						let og_ver = Arc::clone(&og.lock().unwrap().version);
+						let state_ver = Arc::clone(&state_ver);
+						let update = Arc::clone(&update);
+						let update_thread = Arc::clone(&update);
 						thread::spawn(move|| {
 							info!("Spawning update thread...");
-							match Update::start(update.clone(), version) {
+							match Update::start(update_thread, og_ver.clone(), state_ver.clone()) {
 								Err(e) => {
-									info!("Update | {} ... FAIL", e);
+									info!("Update ... {} ... FAIL", e);
 									*update.lock().unwrap().msg.lock().unwrap() = format!("{} | {}", MSG_FAILED, e);
-									*update.lock().unwrap().updating.lock().unwrap() = false;
 								},
-								_ => (),
-							}
+								_ => {
+									info!("Update | Saving state...");
+									match State::save(&mut og.lock().unwrap()) {
+										Ok(_) => info!("Update ... OK"),
+										Err(e) => {
+											warn!("Update | Saving state ... FAIL ... {}", e);
+											*update.lock().unwrap().msg.lock().unwrap() = format!("Saving new versions into state failed");
+										},
+									};
+								}
+							};
+							*update.lock().unwrap().updating.lock().unwrap() = false;
 						});
 					}
 				});
 				ui.vertical(|ui| {
 					ui.set_enabled(updating);
-					let msg = format!("{}\n{}{}", *update.msg.lock().unwrap(), *update.prog.lock().unwrap(), "%");
+					let prog = *update.lock().unwrap().prog.lock().unwrap();
+					let msg = format!("{}\n{}{}", *update.lock().unwrap().msg.lock().unwrap(), prog, "%");
 					ui.add_sized([width, height*1.4], egui::Label::new(msg));
 					let height = height/2.0;
 					if updating {
@@ -66,7 +80,7 @@ impl Gupax {
 					} else {
 						ui.add_sized([width, height], egui::Label::new("..."));
 					}
-					ui.add_sized([width, height], egui::ProgressBar::new((update.prog.lock().unwrap().round() / 100.0)));
+					ui.add_sized([width, height], egui::ProgressBar::new((update.lock().unwrap().prog.lock().unwrap().round() / 100.0)));
 				});
 		});
 
diff --git a/src/main.rs b/src/main.rs
index da8b77e..32832b7 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -16,7 +16,7 @@
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
 // Hide console in Windows
-#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+//#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
 
 //---------------------------------------------------------------------------------------------------- Imports
 // egui/eframe
@@ -70,10 +70,10 @@ pub struct App {
 	width: f32, // Top-level width
 	height: f32, // Top-level height
 	// State
-	og: State, // og    = Old state to compare against
+	og: Arc<Mutex<State>>, // og = Old state to compare against
 	state: State, // state = Working state (current settings)
-	update: Update, // State for update data [update.rs]
-	diff: bool, // Instead of comparing [og == state] every frame, this bool indicates changes
+	update: Arc<Mutex<Update>>, // State for update data [update.rs]
+	diff: bool, // This bool indicates state changes
 	// Process/update state:
 	// Doesn't make sense to save this on disk
 	// so it's represented as a bool here.
@@ -113,9 +113,9 @@ impl App {
 			width: 1280.0,
 			height: 720.0,
 			node: Arc::new(Mutex::new(NodeStruct::default())),
-			og: State::default(),
+			og: Arc::new(Mutex::new(State::default())),
 			state: State::default(),
-			update: Update::new(PathBuf::new(), PathBuf::new(), true),
+			update: Arc::new(Mutex::new(Update::new(PathBuf::new(), PathBuf::new(), true))),
 			diff: false,
 			p2pool: false,
 			xmrig: false,
@@ -141,16 +141,23 @@ impl App {
 		// Read disk state if no [--reset] arg
 		if app.reset == false {
 			app.og = match State::get() {
-				Ok(toml) => toml,
+				Ok(toml) => Arc::new(Mutex::new(toml)),
 				Err(err) => { panic_main(err.to_string()); exit(1); },
 			};
 		}
-		app.state = app.og.clone();
+		app.state = app.og.lock().unwrap().clone();
 		// Handle max threads
-		app.og.xmrig.max_threads = num_cpus::get();
-		if app.og.xmrig.current_threads > app.og.xmrig.max_threads { app.og.xmrig.current_threads = app.og.xmrig.max_threads; }
+		app.og.lock().unwrap().xmrig.max_threads = num_cpus::get();
+		let current = app.og.lock().unwrap().xmrig.current_threads;
+		let max = app.og.lock().unwrap().xmrig.max_threads;
+		if current > max {
+			app.og.lock().unwrap().xmrig.current_threads = max;
+		}
 		// Apply TOML values to [Update]
-		app.update = Update::new(app.og.gupax.absolute_p2pool_path.clone(), app.og.gupax.absolute_xmrig_path.clone(), app.og.gupax.update_via_tor);
+		let p2pool_path = app.og.lock().unwrap().gupax.absolute_p2pool_path.clone();
+		let xmrig_path = app.og.lock().unwrap().gupax.absolute_xmrig_path.clone();
+		let tor = app.og.lock().unwrap().gupax.update_via_tor;
+		app.update = Arc::new(Mutex::new(Update::new(p2pool_path, xmrig_path, tor)));
 		app
 	}
 }
@@ -304,6 +311,22 @@ pub fn get_rand_tmp(path: &String) -> String {
 	path
 }
 
+// Clean any [gupax_tmp.*] directories
+pub fn clean_dir() -> Result<(), anyhow::Error> {
+	for entry in std::fs::read_dir(get_exe_dir()?)? {
+		let entry = entry?;
+		entry.path().is_dir() && continue;
+		if entry.file_name().to_str().ok_or(anyhow::Error::msg("Basename failed"))?.starts_with("gupax_tmp_") {
+			let path = entry.path();
+			match std::fs::remove_dir_all(&path) {
+				Ok(_) => info!("Remove [{}] ... OK", path.display()),
+				Err(e) => warn!("Remove [{}] ... FAIL ... {}", path.display(), e),
+			}
+		}
+	}
+	Ok(())
+}
+
 //---------------------------------------------------------------------------------------------------- [App] frame for [Panic] situations
 fn panic_main(error: String) {
 	error!("{}", error);
@@ -358,6 +381,10 @@ impl eframe::App for Panic {
 fn main() {
 	init_logger();
 	let options = init_options();
+	match clean_dir() {
+		Ok(_) => info!("Temporary folder cleanup ... OK"),
+		Err(e) => warn!("Could not cleanup [gupax_tmp] folders: {}", e),
+	}
 	let app = App::new();
 	let name = app.name_version.clone();
 	eframe::run_native(&name, options, Box::new(|cc| Box::new(App::cc(cc, app))),);
@@ -366,7 +393,7 @@ fn main() {
 impl eframe::App for App {
 	fn on_close_event(&mut self) -> bool {
 		self.quit = true;
-		if self.og.gupax.ask_before_quit {
+		if self.og.lock().unwrap().gupax.ask_before_quit {
 			self.quit_confirm
 		} else {
 			true
@@ -390,6 +417,17 @@ impl eframe::App for App {
             frame.set_fullscreen(!info.window_info.fullscreen);
         }
 
+		// If no state diff (og == state), compare and enable if found.
+		// The struct fields are compared directly because [Version]
+		// contains Arc<Mutex>'s that cannot be compared easily.
+		// They don't need to be compared anyway.
+		let og = self.og.lock().unwrap().clone();
+		if og.gupax != self.state.gupax || og.p2pool != self.state.p2pool || og.xmrig != self.state.xmrig {
+			self.diff = true;
+		} else {
+			self.diff = false;
+		}
+
 		// Close confirmation.
 		if self.quit {
 			// If [ask_before_quit == true]
@@ -521,12 +559,21 @@ impl eframe::App for App {
 
 				ui.with_layout(egui::Layout::right_to_left(egui::Align::RIGHT), |ui| {
 					ui.group(|ui| {
-						if self.state == self.og {
+						if self.diff == false {
 							ui.set_enabled(false)
 						}
 						let width = width / 2.0;
-						if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() { self.og = self.state.clone(); self.state.save(); }
-						if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() { self.state = self.og.clone(); }
+						if ui.add_sized([width, height], egui::Button::new("Save")).on_hover_text("Save changes").clicked() {
+							self.og.lock().unwrap().gupax = self.state.gupax.clone();
+							self.og.lock().unwrap().p2pool = self.state.p2pool.clone();
+							self.og.lock().unwrap().xmrig = self.state.xmrig.clone();
+							self.og.lock().unwrap().save();
+						}
+						if ui.add_sized([width, height], egui::Button::new("Reset")).on_hover_text("Reset changes").clicked() {
+							self.state.gupax = self.og.lock().unwrap().gupax.clone();
+							self.state.p2pool = self.og.lock().unwrap().p2pool.clone();
+							self.state.xmrig = self.og.lock().unwrap().xmrig.clone();
+						}
 					});
 
 					let width = (ui.available_width() / 3.0) - 6.2;
@@ -615,7 +662,7 @@ impl eframe::App for App {
 					Status::show(self, self.width, self.height, ctx, ui);
 				}
 				Tab::Gupax => {
-					Gupax::show(&mut self.state.gupax, &self.og.gupax, self.width, self.height, &mut self.update, self.og.version.clone(), ctx, ui);
+					Gupax::show(&mut self.state.gupax, &self.og, &self.state.version, &self.update, self.width, self.height, ctx, ui);
 				}
 				Tab::P2pool => {
 					P2pool::show(&mut self.state.p2pool, self.width, self.height, ctx, ui);
diff --git a/src/node.rs b/src/node.rs
index 007cbe9..bbfdbd5 100644
--- a/src/node.rs
+++ b/src/node.rs
@@ -15,7 +15,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <https://www.gnu.org/licenses/>.
 
-use serde_derive::{Serialize,Deserialize};
+use serde::{Serialize,Deserialize};
 use std::time::{Instant,Duration};
 use std::collections::HashMap;
 use std::error::Error;
diff --git a/src/state.rs b/src/state.rs
index 8e71d9a..9cae04d 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -32,7 +32,8 @@ use std::{fs,env};
 use std::fmt::Display;
 use std::path::{Path,PathBuf};
 use std::result::Result;
-use serde_derive::{Serialize,Deserialize};
+use std::sync::{Arc,Mutex};
+use serde::{Serialize,Deserialize};
 use figment::Figment;
 use figment::providers::{Format,Toml};
 use crate::constants::HORIZONTAL;
@@ -81,10 +82,10 @@ impl State {
 				pool: "localhost:3333".to_string(),
 				address: "".to_string(),
 			},
-			version: Version {
-				p2pool: P2POOL_VERSION.to_string(),
-				xmrig: XMRIG_VERSION.to_string(),
-			},
+			version: Arc::new(Mutex::new(Version {
+				p2pool: Arc::new(Mutex::new(P2POOL_VERSION.to_string())),
+				xmrig: Arc::new(Mutex::new(XMRIG_VERSION.to_string())),
+			})),
 		}
 	}
 
@@ -267,13 +268,13 @@ const DIRECTORY: &'static str = "gupax";
 #[cfg(target_os = "windows")]
 pub const DEFAULT_P2POOL_PATH: &'static str = r"P2Pool\p2pool.exe";
 #[cfg(target_os = "macos")]
-pub const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/p2pool";
+pub const DEFAULT_P2POOL_PATH: &'static str = "P2Pool/P2Pool";
 #[cfg(target_os = "linux")]
 pub const DEFAULT_P2POOL_PATH: &'static str = "p2pool/p2pool";
 #[cfg(target_os = "windows")]
 pub const DEFAULT_XMRIG_PATH: &'static str = r"XMRig\xmrig.exe";
 #[cfg(target_os = "macos")]
-pub const DEFAULT_XMRIG_PATH: &'static str = "XMRig/xmrig";
+pub const DEFAULT_XMRIG_PATH: &'static str = "XMRig/XMRig";
 #[cfg(target_os = "linux")]
 pub const DEFAULT_XMRIG_PATH: &'static str = "xmrig/xmrig";
 
@@ -288,12 +289,12 @@ pub enum TomlError {
 }
 
 //---------------------------------------------------------------------------------------------------- Structs
-#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
+#[derive(Clone,Debug,Deserialize,Serialize)]
 pub struct State {
 	pub gupax: Gupax,
 	pub p2pool: P2pool,
 	pub xmrig: Xmrig,
-	pub version: Version,
+	pub version: Arc<Mutex<Version>>,
 }
 
 #[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
@@ -341,8 +342,8 @@ pub struct Xmrig {
 //	pub args: String,
 }
 
-#[derive(Clone,Eq,PartialEq,Debug,Deserialize,Serialize)]
+#[derive(Clone,Debug,Deserialize,Serialize)]
 pub struct Version {
-	pub p2pool: String,
-	pub xmrig: String,
+	pub p2pool: Arc<Mutex<String>>,
+	pub xmrig: Arc<Mutex<String>>,
 }
diff --git a/src/update.rs b/src/update.rs
index e16c144..8a0f085 100644
--- a/src/update.rs
+++ b/src/update.rs
@@ -38,7 +38,7 @@ use hyper_tls::HttpsConnector;
 use log::*;
 use rand::distributions::Alphanumeric;
 use rand::{thread_rng, Rng};
-use serde_derive::{Serialize,Deserialize};
+use serde::{Serialize,Deserialize};
 use std::io::{Read,Write};
 use std::path::PathBuf;
 use std::sync::{Arc,Mutex};
@@ -47,7 +47,11 @@ use tls_api::{TlsConnector, TlsConnectorBuilder};
 use tokio::io::{AsyncReadExt,AsyncWriteExt};
 use tokio::task::JoinHandle;
 use walkdir::WalkDir;
+
+#[cfg(target_os = "windows")]
 use zip::ZipArchive;
+#[cfg(target_family = "unix")]
+use std::os::unix::fs::OpenOptionsExt;
 
 //---------------------------------------------------------------------------------------------------- Constants
 // Package naming schemes:
@@ -81,26 +85,47 @@ const P2POOL_HASH: &'static str = "sha256sums.txt.asc";
 const XMRIG_HASH: &'static str = "SHA256SUMS";
 
 #[cfg(target_os = "windows")]
-const GUPAX_EXTENSION: &'static str = "-windows-standalone-x64.exe";
+const GUPAX_EXTENSION: &'static str = "-windows-x64-standalone.exe";
 #[cfg(target_os = "windows")]
 const P2POOL_EXTENSION: &'static str = "-windows-x64.zip";
 #[cfg(target_os = "windows")]
 const XMRIG_EXTENSION: &'static str = "-msvc-win64.zip";
 
 #[cfg(target_os = "macos")]
-const GUPAX_EXTENSION: &'static str = "-macos-standalone-x64";
+const GUPAX_EXTENSION: &'static str = "-macos-x64-standalone";
 #[cfg(target_os = "macos")]
 const P2POOL_EXTENSION: &'static str = "-macos-x64.tar.gz";
 #[cfg(target_os = "macos")]
 const XMRIG_EXTENSION: &'static str = "-macos-x64.tar.gz";
 
 #[cfg(target_os = "linux")]
-const GUPAX_EXTENSION: &'static str = "-linux-standalone-x64";
+const GUPAX_EXTENSION: &'static str = "-linux-x64-standalone";
 #[cfg(target_os = "linux")]
 const P2POOL_EXTENSION: &'static str = "-linux-x64.tar.gz";
 #[cfg(target_os = "linux")]
 const XMRIG_EXTENSION: &'static str = "-linux-static-x64.tar.gz";
 
+#[cfg(target_os = "windows")]
+const GUPAX_BINARY: &'static str = "gupax.exe";
+#[cfg(target_os = "macos")]
+const GUPAX_BINARY: &'static str = "Gupax";
+#[cfg(target_os = "linux")]
+const GUPAX_BINARY: &'static str = "gupax";
+
+#[cfg(target_os = "windows")]
+const P2POOL_BINARY: &'static str = "p2pool.exe";
+#[cfg(target_os = "macos")]
+const P2POOL_BINARY: &'static str = "P2Pool";
+#[cfg(target_os = "linux")]
+const P2POOL_BINARY: &'static str = "p2pool";
+
+#[cfg(target_os = "windows")]
+const XMRIG_BINARY: &'static str = "xmrig.exe";
+#[cfg(target_os = "macos")]
+const XMRIG_BINARY: &'static str = "XMRig";
+#[cfg(target_os = "linux")]
+const XMRIG_BINARY: &'static str = "xmrig";
+
 // Some fake Curl/Wget user-agents because GitHub API requires one and a Tor browser
 // user-agent might be fingerprintable without all the associated headers.
 const FAKE_USER_AGENT: [&'static str; 50] = [
@@ -226,7 +251,7 @@ impl Update {
 	// Get a temporary random folder for package download contents
 	// This used to use [std::env::temp_dir()] but there were issues
 	// using [std::fs::rename()] on tmpfs -> disk (Invalid cross-device link (os error 18)).
-	// So, uses the [Gupax] binary directory as a base, something like [/home/hinto/gupax/gupax_SG4xsDdVmr]
+	// So, uses the [Gupax] binary directory as a base, something like [/home/hinto/gupax/gupax_tmp_SG4xsDdVmr]
 	pub fn get_tmp_dir() -> Result<String, anyhow::Error> {
 		let rand_string: String = thread_rng()
 			.sample_iter(&Alphanumeric)
@@ -235,9 +260,9 @@ impl Update {
 			.collect();
 		let base = crate::get_exe_dir()?;
 		#[cfg(target_os = "windows")]
-		let tmp_dir = format!("{}{}{}{}", base, r"\gupax_", rand_string, r"\");
+		let tmp_dir = format!("{}{}{}{}", base, r"\gupax_tmp_", rand_string, r"\");
 		#[cfg(target_family = "unix")]
-		let tmp_dir = format!("{}{}{}{}", base, "/gupax_", rand_string, "/");
+		let tmp_dir = format!("{}{}{}{}", base, "/gupax_tmp_", rand_string, "/");
 		info!("Update | Temporary directory ... {}", tmp_dir);
 		Ok(tmp_dir)
 	}
@@ -281,7 +306,7 @@ impl Update {
 	// 5. extract, upgrade
 
 	#[tokio::main]
-	pub async fn start(update: Arc<Mutex<Self>>, mut version: Version) -> Result<(), anyhow::Error> {
+	pub async fn start(update: Arc<Mutex<Self>>, og_ver: Arc<Mutex<Version>>, state_ver: Arc<Mutex<Version>>) -> Result<(), anyhow::Error> {
 		//---------------------------------------------------------------------------------------------------- Init
 		*update.lock().unwrap().updating.lock().unwrap() = true;
 		// Set timer
@@ -408,28 +433,30 @@ impl Update {
 			match pkg.name {
 				Gupax  => {
 					if new_ver == GUPAX_VERSION {
-						info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION);
+						info!("Update | {} {} == {} ... SKIPPING", pkg.name, GUPAX_VERSION, new_ver);
 					} else {
-						info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), GUPAX_VERSION);
-						new_pkgs.push(format!("\nGupax {}  ➡  {}", GUPAX_VERSION, pkg.new_ver.lock().unwrap()));
+						info!("Update | {} {} != {} ... ADDING", pkg.name, GUPAX_VERSION, new_ver);
+						new_pkgs.push(format!("\nGupax {}  ➡  {}", GUPAX_VERSION, new_ver));
 						vec3.push(pkg);
 					}
 				}
 				P2pool => {
-					if new_ver == version.p2pool {
-						info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool);
+					let old_ver = og_ver.lock().unwrap().p2pool.lock().unwrap().to_owned();
+					if old_ver == new_ver {
+						info!("Update | {} {} == {} ... SKIPPING", pkg.name, old_ver, new_ver);
 					} else {
-						info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.p2pool);
-						new_pkgs.push(format!("\nP2Pool {}  ➡  {}", version.p2pool, pkg.new_ver.lock().unwrap()));
+						info!("Update | {} {} != {} ... ADDING", pkg.name, old_ver, new_ver);
+						new_pkgs.push(format!("\nP2Pool {}  ➡  {}", old_ver, new_ver));
 						vec3.push(pkg);
 					}
 				}
 				Xmrig  => {
-					if new_ver == GUPAX_VERSION {
-						info!("Update | {} {} == {} ... SKIPPING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig);
+					let old_ver = og_ver.lock().unwrap().xmrig.lock().unwrap().to_owned();
+					if old_ver == new_ver {
+						info!("Update | {} {} == {} ... SKIPPING", pkg.name, old_ver, new_ver);
 					} else {
-						info!("Update | {} {} != {} ... ADDING", pkg.name, pkg.new_ver.lock().unwrap(), version.xmrig);
-						new_pkgs.push(format!("\nXMRig {}  ➡  {}", version.xmrig, pkg.new_ver.lock().unwrap()));
+						info!("Update | {} {} != {} ... ADDING", pkg.name, old_ver, new_ver);
+						new_pkgs.push(format!("\nXMRig {}  ➡  {}", old_ver, new_ver));
 						vec3.push(pkg);
 					}
 				}
@@ -522,14 +549,13 @@ impl Update {
 		*update.lock().unwrap().msg.lock().unwrap() = format!("{}{}", MSG_EXTRACT, new_pkgs);
 		info!("Update | {}", EXTRACT);
 		for pkg in vec4.iter() {
-			let tmp = tmp_dir.to_owned() + &pkg.name.to_string();
 			if pkg.name == Name::Gupax {
+				let tmp = tmp_dir.to_owned() + GUPAX_BINARY;
 				#[cfg(target_family = "unix")]
-				use std::os::unix::fs::OpenOptionsExt;
-				#[cfg(target_family = "unix")]
-				std::fs::OpenOptions::new().create(true).write(true).mode(0o770).open(&tmp)?;
+				std::fs::OpenOptions::new().create(true).write(true).mode(0o750).open(&tmp)?;
 				std::fs::write(tmp, pkg.bytes.lock().unwrap().as_ref())?;
 			} else {
+				let tmp = tmp_dir.to_owned() + &pkg.name.to_string();
 				#[cfg(target_os = "windows")]
 				ZipArchive::extract(&mut ZipArchive::new(std::io::Cursor::new(pkg.bytes.lock().unwrap().as_ref()))?, tmp)?;
 				#[cfg(target_family = "unix")]
@@ -553,46 +579,55 @@ impl Update {
 			let entry = entry?.clone();
 			let basename = entry.file_name().to_str().ok_or(anyhow::Error::msg("WalkDir basename failed"))?;
 			match basename {
-				"Gupax" => {
+				GUPAX_BINARY => {
 					let path = update.lock().unwrap().path_gupax.clone();
 					info!("Update | Moving [{}] -> [{}]", entry.path().display(), path);
+					// Unix can replace running binaries no problem (they're loading into memory)
+					// Windows locks binaries in place, so we must move (rename) current binary
+					// into the temp folder, then move the new binary into the old ones spot.
+					// Clearing the temp folder is now moved at startup instead at the end
+					// of this function due to this behavior, thanks Windows.
+					#[cfg(target_os = "windows")]
+					std::fs::rename(&path, tmp_dir.clone() + "gupax_old.exe")?;
 					std::fs::rename(entry.path(), path)?;
 					*update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round();
 				},
-				"p2pool" => {
+				P2POOL_BINARY => {
 					let path = update.lock().unwrap().path_p2pool.clone();
 					let path = std::path::Path::new(&path);
 					info!("Update | Moving [{}] -> [{}]", entry.path().display(), path.display());
 					std::fs::create_dir_all(path.parent().ok_or(anyhow::Error::msg("P2Pool path failed"))?)?;
 					std::fs::rename(entry.path(), path)?;
-					version.p2pool = Pkg::get_new_pkg_version(P2pool, &vec4)?;
+					*og_ver.lock().unwrap().p2pool.lock().unwrap() = Pkg::get_new_pkg_version(P2pool, &vec4)?;
 					*update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round();
 				},
-				"xmrig" => {
+				XMRIG_BINARY => {
 					let path = update.lock().unwrap().path_xmrig.clone();
 					let path = std::path::Path::new(&path);
 					info!("Update | Moving [{}] -> [{}]", entry.path().display(), path.display());
 					std::fs::create_dir_all(path.parent().ok_or(anyhow::Error::msg("XMRig path failed"))?)?;
 					std::fs::rename(entry.path(), path)?;
-					version.xmrig = Pkg::get_new_pkg_version(Xmrig, &vec4)?;
+					*og_ver.lock().unwrap().xmrig.lock().unwrap() = Pkg::get_new_pkg_version(Xmrig, &vec4)?;
 					*update.lock().unwrap().prog.lock().unwrap() += (5.0 / pkg_amount).round();
 				},
 				_ => (),
 			}
 		}
 
+		// Remove tmp dir (on Unix)
+		#[cfg(target_family = "unix")]
 		info!("Update | Removing temporary directory ... {}", tmp_dir);
+		#[cfg(target_family = "unix")]
 		std::fs::remove_dir_all(&tmp_dir)?;
+
 		let seconds = now.elapsed().as_secs();
-		info!("Update ... Seconds elapsed: [{}s]", seconds);
-		info!("Update ... OK ... 100%");
+		info!("Update | Seconds elapsed ... [{}s]", seconds);
 		match seconds {
 			0 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 0 seconds... Do you have 10Gbit internet or something...?!{}", MSG_SUCCESS, new_pkgs),
 			1 => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took 1 second... Wow!{}", MSG_SUCCESS, new_pkgs),
 			_ => *update.lock().unwrap().msg.lock().unwrap() = format!("{}! Took {} seconds.{}", MSG_SUCCESS, seconds, new_pkgs),
 		}
 		*update.lock().unwrap().prog.lock().unwrap() = 100.0;
-		*update.lock().unwrap().updating.lock().unwrap() = false;
 		Ok(())
 	}
 }