mirror of
https://github.com/corpnewt/gibMacOS.git
synced 2024-11-14 10:15:28 +01:00
774 lines
34 KiB
Python
Executable File
774 lines
34 KiB
Python
Executable File
from Scripts import *
|
|
import os, sys, tempfile, shutil, zipfile, platform, json, time
|
|
|
|
class WinUSB:
|
|
|
|
def __init__(self):
|
|
self.u = utils.Utils("MakeInstall")
|
|
self.min_plat = 9600
|
|
# Make sure we're on windows
|
|
self.verify_os()
|
|
# Setup initial vars
|
|
self.d = diskwin.Disk()
|
|
self.dl = downloader.Downloader()
|
|
self.r = run.Run()
|
|
self.scripts = "Scripts"
|
|
self.s_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), self.scripts)
|
|
self.dd_url = "http://www.chrysocome.net/downloads/ddrelease64.exe"
|
|
self.dd_name = os.path.basename(self.dd_url)
|
|
self.z_json = "https://sourceforge.net/projects/sevenzip/best_release.json"
|
|
self.z_url2 = "https://www.7-zip.org/a/7z1806-x64.msi"
|
|
self.z_url = "https://www.7-zip.org/a/7z[[vers]]-x64.msi"
|
|
self.z_name = "7z.exe"
|
|
self.z_reg = [
|
|
{
|
|
"loc" : "HKLM\\Software\\Classes\\CLSID\\{23170F69-40C1-278A-1000-000100020000}",
|
|
"val" : "7-Zip Shell Extension"
|
|
},
|
|
{
|
|
"loc" : "HKLM\\Software\\Classes\\CLSID\\{23170F69-40C1-278A-1000-000100020000}\InprocServer32",
|
|
"name": "ThreadingModel",
|
|
"val" : "Apartment"
|
|
},
|
|
{
|
|
"loc" : "HKLM\\Software\\Classes\\*\\shellex\\ContextMenuHanders\\7-Zip",
|
|
"val" : "{23170F69-40C1-278A-1000-000100020000}"
|
|
},
|
|
{
|
|
"loc" : "HKLM\\Software\\Classes\\Directory\\shellex\\ContextMenuHanders\\7-Zip",
|
|
"val" : "{23170F69-40C1-278A-1000-000100020000}"
|
|
},
|
|
{
|
|
"loc" : "HKLM\\Software\\Classes\\Folder\\shellex\\ContextMenuHanders\\7-Zip",
|
|
"val" : "{23170F69-40C1-278A-1000-000100020000}"
|
|
},
|
|
]
|
|
self.bi_url = "https://sites.google.com/site/gbrtools/home/software/bootice-portable/files/BOOTICE_v1.3.3.2.zip"
|
|
self.bi_name = "BOOTICEx64.exe"
|
|
self.clover_url = "https://api.github.com/repos/dids/clover-builder/releases/latest"
|
|
# From Tim Sutton's brigadier: https://github.com/timsutton/brigadier/blob/master/brigadier
|
|
self.z_path = None
|
|
self.z_path64 = os.path.join(os.environ['SYSTEMDRIVE'] + "\\", "Program Files", "7-Zip", "7z.exe")
|
|
self.z_path32 = os.path.join(os.environ['SYSTEMDRIVE'] + "\\", "Program Files (x86)", "7-Zip", "7z.exe")
|
|
self.recovery_suffixes = (
|
|
"recoveryhdupdate.pkg",
|
|
"recoveryhdmetadmg.pkg"
|
|
)
|
|
self.dd_bootsector = True
|
|
self.boot0 = "boot0af"
|
|
self.boot1 = "boot1f32alt"
|
|
self.boot = "boot6"
|
|
self.efi_id = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" # EFI
|
|
self.bas_id = "ebd0a0a2-b9e5-4433-87c0-68b6b72699c7" # Microsoft Basic Data
|
|
self.hfs_id = "48465300-0000-11AA-AA11-00306543ECAC" # HFS+
|
|
self.rec_id = "426F6F74-0000-11AA-AA11-00306543ECAC" # Apple Boot partition (Recovery HD)
|
|
|
|
def verify_os(self):
|
|
self.u.head("Verifying OS")
|
|
print("")
|
|
print("Verifying OS name...")
|
|
if not os.name=="nt":
|
|
print("")
|
|
print("This script is only for Windows!")
|
|
print("")
|
|
self.u.grab("Press [enter] to exit...")
|
|
exit(1)
|
|
print(" - Name = NT")
|
|
print("Verifying OS version...")
|
|
# Verify we're at version 9600 or greater
|
|
try:
|
|
# Set plat to the last item of the output split by . - looks like:
|
|
# Windows-8.1-6.3.9600
|
|
# or this:
|
|
# Windows-10-10.0.17134-SP0
|
|
plat = int(platform.platform().split(".")[-1].split("-")[0])
|
|
except:
|
|
plat = 0
|
|
if plat < self.min_plat:
|
|
print("")
|
|
print("Currently running {}, this script requires version {} or newer.".format(platform.platform(), self.min_plat))
|
|
print("")
|
|
self.u.grab("Press [enter] to exit...")
|
|
exit(1)
|
|
print(" - Version = {}".format(plat))
|
|
print("")
|
|
print("{} >= {}, continuing...".format(plat, self.min_plat))
|
|
|
|
def get_disks_of_type(self, disk_list, disk_type=(0,2)):
|
|
disks = {}
|
|
for disk in disk_list:
|
|
if disk_list[disk].get("type",0) in disk_type:
|
|
disks[disk] = disk_list[disk]
|
|
return disks
|
|
|
|
def check_dd(self):
|
|
# Checks if ddrelease64.exe exists in our Scripts dir
|
|
# and if not - downloads it
|
|
#
|
|
# Returns True if exists/downloaded successfully
|
|
# or False if issues.
|
|
# Check for dd.exe in the current dir
|
|
if os.path.exists(os.path.join(self.s_path, self.dd_name)):
|
|
# print("Located {}!".format(self.dd_name))
|
|
# Got it
|
|
return True
|
|
print("Couldn't locate {} - downloading...".format(self.dd_name))
|
|
# Now we need to download
|
|
self.dl.stream_to_file(self.dd_url, os.path.join(self.s_path, self.dd_name))
|
|
print("")
|
|
return os.path.exists(os.path.join(self.s_path, self.dd_name))
|
|
|
|
def check_7z(self):
|
|
# Check for 7z.exe in Program Files and if not - download the 7z msi and install
|
|
#
|
|
# Returns True if found, False if not
|
|
if os.path.exists(self.z_path64):
|
|
# Got it
|
|
self.z_path = self.z_path64
|
|
return True
|
|
elif os.path.exists(self.z_path32):
|
|
# Found the 32 bit version
|
|
self.z_path = self.z_path32
|
|
return True
|
|
print("Didn't locate {} - downloading...".format(self.z_name))
|
|
# Didn't find it - let's do some stupid stuff
|
|
# First we get our json response - or rather, try to, then parse it
|
|
# looking for the current version
|
|
dl_url = None
|
|
try:
|
|
json = json.loads(self.dl.get_string(self.z_json))
|
|
v_num = json.get("release",{}).get("filename","").split("/")[-1].lower().replace("7z","").replace(".exe","")
|
|
if len(v_num):
|
|
dl_url = self.url.replace("[[vers]]",v_num)
|
|
except:
|
|
pass
|
|
if not dl_url:
|
|
dl_url = self.z_url2
|
|
temp = tempfile.mkdtemp()
|
|
self.dl.stream_to_file(dl_url, os.path.join(temp, self.z_name))
|
|
print("")
|
|
print("Installing 7zip...")
|
|
# From Tim Sutton's brigadier: https://github.com/timsutton/brigadier/blob/master/brigadier
|
|
self.r.run({"args":["msiexec", "/qn", "/i", os.path.join(temp, self.z_name)],"stream":True})
|
|
print("Setting reg entries...")
|
|
for x in self.z_reg:
|
|
if not "val" in x or not "loc" in x:
|
|
continue
|
|
args = ["reg.exe","add",x["loc"]]
|
|
if x.get("name",None):
|
|
args.extend(["/v",x["name"]])
|
|
if x.get("type",None):
|
|
args.extend(["/t",x["type"]])
|
|
if x.get("val",None):
|
|
args.extend(["/d",x["val"]])
|
|
args.append("/f")
|
|
out = self.r.run({"args":args})
|
|
if out[2] != 0:
|
|
print("Error: {}".format(out[1]))
|
|
print("")
|
|
self.u.grab("Press [enter] to exit...")
|
|
print("")
|
|
return os.path.exists(self.z_path)
|
|
|
|
def check_bi(self):
|
|
# Checks for BOOTICEx64.exe in our scripts dir
|
|
# and downloads it if need be
|
|
if os.path.exists(os.path.join(self.s_path, self.bi_name)):
|
|
# print("Located {}!".format(self.bi_name))
|
|
# Got it
|
|
return True
|
|
print("Couldn't locate {} - downloading...".format(self.bi_name))
|
|
temp = tempfile.mkdtemp()
|
|
zfile = os.path.basename(self.bi_url)
|
|
print("Downloading {}...".format(os.path.basename(self.bi_url)))
|
|
self.dl.stream_to_file(self.bi_url, os.path.join(temp,zfile))
|
|
print("")
|
|
print(" - Extracting...")
|
|
# Extract with built-in tools \o/
|
|
os.chdir(temp)
|
|
with zipfile.ZipFile(os.path.join(temp,zfile)) as z:
|
|
z.extractall(temp)
|
|
for x in os.listdir(temp):
|
|
if self.bi_name.lower() in x.lower():
|
|
# Found it
|
|
print(" - Found {}".format(x))
|
|
print(" - Copying to {} directory...".format(self.scripts))
|
|
shutil.copy(os.path.join(temp,x), os.path.join(self.s_path,x))
|
|
# Return the cd to the local script dir
|
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
|
# Remove the temp folder
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
return os.path.exists(os.path.join(self.s_path,self.bi_name))
|
|
|
|
def get_dl_info(self):
|
|
# Returns the latest download package and info in a
|
|
# dictionary: { "url" : dl_url, "name" : name, "info" : update_info }
|
|
json_data = self.dl.get_string(self.clover_url, False)
|
|
if not json_data or not len(json_data):
|
|
return None
|
|
try:
|
|
j = json.loads(json_data)
|
|
except:
|
|
return None
|
|
dl_link = next((x.get("browser_download_url", None) for x in j.get("assets", []) if x.get("browser_download_url", "").lower().endswith(".lzma")), None)
|
|
if not dl_link:
|
|
return None
|
|
return { "url" : dl_link, "name" : os.path.basename(dl_link), "info" : j.get("body", None) }
|
|
|
|
def get_size(self, size):
|
|
# Returns the size passed as human readable
|
|
if size == -1:
|
|
return "Unknown"
|
|
ext = ["B","KB","MB","GB","TB","PB"]
|
|
s = float(size)
|
|
s_dict = {}
|
|
# Iterate the ext list, and divide by 1000 each time
|
|
for e in ext:
|
|
s_dict[e] = s
|
|
s /= 1000
|
|
# Get the maximum >= 1 type
|
|
biggest = next((x for x in ext[::-1] if s_dict[x] >= 1), "B")
|
|
# Round to 2 decimal places
|
|
bval = round(s_dict[biggest], 2)
|
|
# Strip any orphaned, trailing 0's
|
|
non_zero = False
|
|
z_list = []
|
|
for z in str(bval).split(".")[1][::-1]:
|
|
if z == "0" and not non_zero:
|
|
# We have a zero - and haven't hit a non-zero yet
|
|
continue
|
|
# Either got a non-zero, or non_zero is already set
|
|
non_zero = True # Set again - just in case
|
|
z_list.append(z)
|
|
if len(z_list):
|
|
return "{}.{} {}".format(str(bval).split(".")[0], "".join(z_list[::-1]), biggest)
|
|
else:
|
|
return "{} {}".format(str(bval).split(".")[0], biggest)
|
|
|
|
def diskpart_flag(self, disk, as_efi=False):
|
|
# Sets and unsets the GUID needed for a GPT EFI partition ID
|
|
self.u.head("Changing ID With DiskPart")
|
|
print("")
|
|
print("Setting type as {}...".format("EFI" if as_efi else "Basic Data"))
|
|
print("")
|
|
# - EFI system partition: c12a7328-f81f-11d2-ba4b-00a0c93ec93b
|
|
# - Basic data partition: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
|
|
dp_script = "\n".join([
|
|
"select disk {}".format(disk.get("index",-1)),
|
|
"sel part 1",
|
|
"set id={}".format(self.efi_id if as_efi else self.bas_id)
|
|
])
|
|
temp = tempfile.mkdtemp()
|
|
script = os.path.join(temp, "diskpart.txt")
|
|
try:
|
|
with open(script,"w") as f:
|
|
f.write(dp_script)
|
|
except:
|
|
shutil.rmtree(temp)
|
|
print("Error creating script!")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Let's try to run it!
|
|
out = self.r.run({"args":["diskpart","/s",script],"stream":True})
|
|
# Ditch our script regardless of whether diskpart worked or not
|
|
shutil.rmtree(temp)
|
|
print("")
|
|
if out[2] != 0:
|
|
# Error city!
|
|
print("DiskPart exited with non-zero status ({}). Aborting.".format(out[2]))
|
|
else:
|
|
print("Done - You may need to replug your drive for the")
|
|
print("changes to take effect.")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
|
|
def diskpart_erase(self, disk, gpt=False):
|
|
# Generate a script that we can pipe to diskpart to erase our disk
|
|
self.u.head("Erasing With DiskPart")
|
|
print("")
|
|
# Then we'll re-gather our disk info on success and move forward
|
|
# Using MBR to effectively set the individual partition types
|
|
# Keeps us from having issues mounting the EFI on Windows -
|
|
# and also lets us explicitly set the partition id for the main
|
|
# data partition.
|
|
if not gpt:
|
|
print("Using MBR...")
|
|
dp_script = "\n".join([
|
|
"select disk {}".format(disk.get("index",-1)),
|
|
"clean",
|
|
"convert mbr",
|
|
"create partition primary size=200",
|
|
"format quick fs=fat32 label='CLOVER'",
|
|
"active",
|
|
"create partition primary id=AB" # AF = HFS, AB = Recovery
|
|
])
|
|
else:
|
|
print("Using GPT...")
|
|
dp_script = "\n".join([
|
|
"select disk {}".format(disk.get("index",-1)),
|
|
"clean",
|
|
"convert gpt",
|
|
"create partition primary size=200",
|
|
"format quick fs=fat32 label='CLOVER'",
|
|
"create partition primary id={}".format(self.hfs_id)
|
|
])
|
|
temp = tempfile.mkdtemp()
|
|
script = os.path.join(temp, "diskpart.txt")
|
|
try:
|
|
with open(script,"w") as f:
|
|
f.write(dp_script)
|
|
except:
|
|
shutil.rmtree(temp)
|
|
print("Error creating script!")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Let's try to run it!
|
|
out = self.r.run({"args":["diskpart","/s",script],"stream":True})
|
|
# Ditch our script regardless of whether diskpart worked or not
|
|
shutil.rmtree(temp)
|
|
if out[2] != 0:
|
|
# Error city!
|
|
print("")
|
|
print("DiskPart exited with non-zero status ({}). Aborting.".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# We should now have a fresh drive to work with
|
|
# Let's write an image or something
|
|
self.u.head("Updating Disk Information")
|
|
print("")
|
|
print("Re-populating list...")
|
|
self.d.update()
|
|
print("Relocating disk {}".format(disk["index"]))
|
|
disk = self.d.disks[str(disk["index"])]
|
|
self.select_package(disk)
|
|
|
|
def select_package(self, disk):
|
|
self.u.head("Select Recovery Package")
|
|
print("")
|
|
print("{}. {} - {} ({})".format(
|
|
disk.get("index",-1),
|
|
disk.get("model","Unknown"),
|
|
self.get_size(disk.get("size",-1)),
|
|
["Unknown","No Root Dir","Removable","Local","Network","Disc","RAM Disk"][disk.get("type",0)]
|
|
))
|
|
print("")
|
|
print("M. Main Menu")
|
|
print("Q. Quit")
|
|
print("")
|
|
menu = self.u.grab("Please paste the recovery update pkg path to extract: ")
|
|
if menu.lower() == "q":
|
|
self.u.custom_quit()
|
|
if menu.lower() == "m":
|
|
return
|
|
path = self.u.check_path(menu)
|
|
if not path:
|
|
self.select_package(disk)
|
|
return
|
|
# Got the package - let's make sure it's named right - just in case
|
|
if os.path.basename(path).lower().endswith(".hfs"):
|
|
# We have an hfs image already - bypass extraction
|
|
self.dd_image(disk, path)
|
|
return
|
|
# If it's a directory, find the first recovery hit
|
|
if os.path.isdir(path):
|
|
for f in os.listdir(path):
|
|
if f.lower().endswith(self.recovery_suffixes):
|
|
path = os.path.join(path, f)
|
|
break
|
|
# Make sure it's named right for recovery stuffs
|
|
if not path.lower().endswith(self.recovery_suffixes):
|
|
self.u.head("Invalid Package")
|
|
print("")
|
|
print("{} is not in the available recovery package names:\n{}".format(os.path.basename(path), ", ".join(self.recovery_suffixes)))
|
|
print("")
|
|
print("Ensure you're passing a proper recovery package.")
|
|
print("")
|
|
self.u.grab("Press [enter] to return to package selection...")
|
|
self.select_package(disk)
|
|
return
|
|
self.u.head("Extracting Package")
|
|
print("")
|
|
temp = tempfile.mkdtemp()
|
|
cwd = os.getcwd()
|
|
os.chdir(temp)
|
|
# Extract in sections and remove any files we run into
|
|
print("Extracting Recovery dmg...")
|
|
out = self.r.run({"args":[self.z_path, "e", "-txar", path, "*.dmg"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Extracting BaseSystem.dmg...")
|
|
# No files to delete here - let's extract the next part
|
|
out = self.r.run({"args":[self.z_path, "e", "*.dmg", "*/Base*.dmg"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# If we got here - we should delete everything in the temp folder except
|
|
# for a .dmg that starts with Base
|
|
del_list = [x for x in os.listdir(temp) if not (x.lower().startswith("base") and x.lower().endswith(".dmg"))]
|
|
for d in del_list:
|
|
os.remove(os.path.join(temp, d))
|
|
# Onto the last command
|
|
print("Extracting hfs...")
|
|
out = self.r.run({"args":[self.z_path, "e", "-tdmg", "Base*.dmg", "*.hfs"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# If we got here - we should delete everything in the temp folder except
|
|
# for a .dmg that starts with Base
|
|
del_list = [x for x in os.listdir(temp) if not x.lower().endswith(".hfs")]
|
|
for d in del_list:
|
|
os.remove(os.path.join(temp, d))
|
|
print("Extracted successfully!")
|
|
hfs = next((x for x in os.listdir(temp) if x.lower().endswith(".hfs")),None)
|
|
# Now to dd our image - if it exists
|
|
if not hfs:
|
|
print("Missing the .hfs file! Aborting.")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
else:
|
|
self.dd_image(disk, os.path.join(temp, hfs))
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
|
|
def dd_image(self, disk, image):
|
|
# Let's dd the shit out of our disk
|
|
self.u.head("Copying Image To Drive")
|
|
print("")
|
|
print("Image: {}".format(image))
|
|
print("")
|
|
print("Disk {}. {} - {} ({})".format(
|
|
disk.get("index",-1),
|
|
disk.get("model","Unknown"),
|
|
self.get_size(disk.get("size",-1)),
|
|
["Unknown","No Root Dir","Removable","Local","Network","Disc","RAM Disk"][disk.get("type",0)]
|
|
))
|
|
print("")
|
|
args = [
|
|
os.path.join(self.s_path, self.dd_name),
|
|
"if={}".format(image),
|
|
"of=\\\\?\\Device\Harddisk{}\Partition2".format(disk.get("index",-1)),
|
|
"bs=8M",
|
|
"--progress"
|
|
]
|
|
print(" ".join(args))
|
|
print("")
|
|
print("This may take some time!")
|
|
print("")
|
|
out = self.r.run({"args":args})
|
|
if len(out[1].split("Error")) > 1:
|
|
# We had some error text - dd, even when failing likes to give us a 0
|
|
# status code. It also sends a ton of text through stderr - so we comb
|
|
# that for "Error" then split by that to skip the extra fluff and show only
|
|
# the error.
|
|
print("An error occurred:\n\n{}".format("Error"+out[1].split("Error")[1]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return to the main menu...")
|
|
return
|
|
# Install Clover to the target drive
|
|
self.install_clover(disk)
|
|
|
|
def install_clover(self, disk):
|
|
self.u.head("Installing Clover")
|
|
print("")
|
|
print("Gathering info...")
|
|
c = self.get_dl_info()
|
|
if c == None:
|
|
print(" - Error communicating with github!")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print(" - Got {}".format(c.get("name","Unknown Version")))
|
|
print("Downloading...")
|
|
temp = tempfile.mkdtemp()
|
|
os.chdir(temp)
|
|
clover_lzma = c["name"]
|
|
self.dl.stream_to_file(c["url"], os.path.join(temp, c["name"]))
|
|
print("") # Empty space to clear the download progress
|
|
if not os.path.exists(os.path.join(temp, c["name"])):
|
|
print(" - Download failed. Aborting...")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Got a valid file in our temp dir
|
|
print("Extracting {}...".format(clover_lzma))
|
|
out = self.r.run({"args":[self.z_path, "e", os.path.join(temp,clover_lzma)]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Should result in a .tar file
|
|
clover_tar = next((x for x in os.listdir(temp) if x.lower().endswith(".tar")),None)
|
|
if not clover_tar:
|
|
print(" - No .tar archive found - aborting...")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Got the .tar archive - get the .iso
|
|
print("Extracting {}...".format(clover_tar))
|
|
out = self.r.run({"args":[self.z_path, "e", os.path.join(temp,clover_tar)]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Should result in a .iso file
|
|
clover_iso = next((x for x in os.listdir(temp) if x.lower().endswith(".iso")),None)
|
|
if not clover_tar:
|
|
print(" - No .iso found - aborting...")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Got the .iso - let's extract the needed parts
|
|
print("Extracting EFI from {}...".format(clover_iso))
|
|
out = self.r.run({"args":[self.z_path, "x", os.path.join(temp,clover_iso), "EFI*"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Extracting {} from {}...".format(self.boot0,clover_iso))
|
|
out = self.r.run({"args":[self.z_path, "e", os.path.join(temp,clover_iso), self.boot0, "-r"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Extracting {} from {}...".format(self.boot1,clover_iso))
|
|
out = self.r.run({"args":[self.z_path, "e", os.path.join(temp,clover_iso), self.boot1, "-r"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Extracting {} from {}...".format(self.boot,clover_iso))
|
|
out = self.r.run({"args":[self.z_path, "e", os.path.join(temp,clover_iso), self.boot, "-r"]})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred extracting: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# At this point, we should have a boot0xx file and an EFI folder in the temp dir
|
|
# We need to udpate the disk list though - to reflect the current file system on part 1
|
|
# of our current disk
|
|
self.d.update() # assumes our disk number stays the same
|
|
# Some users are having issues with the "partitions" key not populating - possibly a 3rd party disk management soft?
|
|
# Possibly a bad USB?
|
|
# We'll see if the key exists - if not, we'll throw an error.
|
|
if self.d.disks[str(disk["index"])].get("partitions",None) == None:
|
|
# No partitions found.
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("No partitions located on disk!")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
part = self.d.disks[str(disk["index"])]["partitions"].get("0",{}).get("letter",None) # get the first partition's letter
|
|
if part == None:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("Lost original disk - or formatting failed!")
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
# Here we have our disk and partitions and such - the CLOVER partition
|
|
# will be the first partition
|
|
# Let's copy over the EFI folder and then dd the boot0xx file
|
|
print("Copying EFI folder to {}/EFI...".format(part))
|
|
if os.path.exists("{}/EFI".format(part)):
|
|
print(" - EFI exists - removing...")
|
|
shutil.rmtree("{}/EFI".format(part),ignore_errors=True)
|
|
time.sleep(1) # Added because windows is dumb
|
|
shutil.copytree(os.path.join(temp,"EFI"), "{}/EFI".format(part))
|
|
# Copy boot6 over to the root of the EFI volume - and rename it to boot
|
|
print("Copying {} to {}/boot...".format(self.boot,part))
|
|
shutil.copy(os.path.join(temp,self.boot),"{}/boot".format(part))
|
|
# Use bootice to update the MBR and PBR - always on the first
|
|
# partition (which is 0 in bootice)
|
|
print("Updating the MBR with {}...".format(self.boot0))
|
|
args = [
|
|
os.path.join(self.s_path,self.bi_name),
|
|
"/device={}".format(disk.get("index",-1)),
|
|
"/mbr",
|
|
"/restore",
|
|
"/file={}".format(os.path.join(temp,self.boot0)),
|
|
"/keep_dpt",
|
|
"/quiet"
|
|
]
|
|
out = self.r.run({"args":args})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred updating the MBR: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Updating the PBR with {}...".format(self.boot1))
|
|
args = [
|
|
os.path.join(self.s_path,self.bi_name),
|
|
"/device={}:0".format(disk.get("index",-1)),
|
|
"/pbr",
|
|
"/restore",
|
|
"/file={}".format(os.path.join(temp,self.boot1)),
|
|
"/keep_bpb",
|
|
"/quiet"
|
|
]
|
|
out = self.r.run({"args":args})
|
|
if out[2] != 0:
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print(" - An error occurred updating the PBR: {}".format(out[2]))
|
|
print("")
|
|
self.u.grab("Press [enter] to return...")
|
|
return
|
|
print("Cleaning up...")
|
|
shutil.rmtree(temp,ignore_errors=True)
|
|
print("")
|
|
print("Done.")
|
|
print("")
|
|
self.u.grab("Press [enter] to return to the main menu...")
|
|
|
|
def main(self):
|
|
# Start out with our cd in the right spot.
|
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
|
# Let's make sure we have the required files needed
|
|
self.u.head("Checking Required Tools")
|
|
print("")
|
|
if not self.check_dd():
|
|
print("Couldn't find or install {} - aborting!".format(self.dd_name))
|
|
exit(1)
|
|
if not self.check_7z():
|
|
print("Couldn't find or install {} - aborting!".format(self.z_name))
|
|
exit(1)
|
|
if not self.check_bi():
|
|
print("Couldn't find or install {} - aborting!".format(self.bi_name))
|
|
exit(1)
|
|
# Let's just setup a real simple interface and try to write some data
|
|
self.u.head("Gathering Disk Info")
|
|
print("")
|
|
print("Populating list...")
|
|
self.d.update()
|
|
print("")
|
|
print("Done!")
|
|
# Let's serve up a list of *only* removable media
|
|
self.u.head("Potential Removable Media")
|
|
print("")
|
|
rem_disks = self.get_disks_of_type(self.d.disks)
|
|
|
|
# SHOWING ALL DISKS CURRENTLY - CHANGE THIS FOR RELEASE!!!!
|
|
# rem_disks = self.d.disks
|
|
|
|
# Types: 0 = Unknown, 1 = No Root Dir, 2 = Removable, 3 = Local, 4 = Network, 5 = Disc, 6 = RAM disk
|
|
|
|
print("!WARNING! This list includes both Removable AND")
|
|
print("!WARNING! Unknown disk types. Be ABSOLUTELY sure")
|
|
print("!WARNING! before selecting a disk!")
|
|
print("")
|
|
for disk in sorted(rem_disks):
|
|
print("{}. {} - {} ({})".format(
|
|
disk,
|
|
rem_disks[disk].get("model","Unknown"),
|
|
self.get_size(rem_disks[disk].get("size",-1)),
|
|
["Unknown","No Root Dir","Removable","Local","Network","Disc","RAM Disk"][rem_disks[disk].get("type",0)]
|
|
))
|
|
if not len(rem_disks[disk].get("partitions",{})):
|
|
print(" No Mounted Partitions")
|
|
else:
|
|
parts = rem_disks[disk]["partitions"]
|
|
for p in sorted(parts):
|
|
print(" {}. {} ({}) {} - {}".format(
|
|
p,
|
|
parts[p].get("letter","No Letter"),
|
|
"No Name" if not parts[p].get("name",None) else parts[p].get("name","No Name"),
|
|
parts[p].get("file system","Unknown FS"),
|
|
self.get_size(parts[p].get("size",-1))
|
|
))
|
|
print("")
|
|
print("Q. Quit")
|
|
print("")
|
|
print("Usage: [drive][option (only one allowed)] (eg. 1C)")
|
|
print(" Options are as follows with precedence C > E > U > G:")
|
|
print(" C = Only install Clover to the drive's first partition.")
|
|
print(" E = Sets the type of the drive's first partition to EFI.")
|
|
print(" U = Similar to E, but sets the type to Basic Data (useful for editing).")
|
|
print(" G = Format as GPT (default is MBR).")
|
|
print("")
|
|
menu = self.u.grab("Please select a disk or press [enter] with no options to refresh: ")
|
|
if not len(menu):
|
|
self.main()
|
|
return
|
|
if menu.lower() == "q":
|
|
self.u.custom_quit()
|
|
only_clover = set_efi = unset_efi = use_gpt = False
|
|
if "c" in menu.lower():
|
|
only_clover = True
|
|
menu = menu.lower().replace("c","")
|
|
if "e" in menu.lower():
|
|
set_efi = True
|
|
menu = menu.lower().replace("e","")
|
|
if "u" in menu.lower():
|
|
unset_efi = True
|
|
menu = menu.lower().replace("u","")
|
|
if "g" in menu.lower():
|
|
use_gpt = True
|
|
menu = menu.lower().replace("g","")
|
|
|
|
selected_disk = rem_disks.get(menu,None)
|
|
if not selected_disk:
|
|
self.u.head("Invalid Choice")
|
|
print("")
|
|
print("Disk {} is not an option.".format(menu))
|
|
print("")
|
|
self.u.grab("Returning in 5 seconds...", timeout=5)
|
|
self.main()
|
|
return
|
|
# Got a disk!
|
|
if only_clover:
|
|
self.install_clover(selected_disk)
|
|
elif set_efi:
|
|
self.diskpart_flag(selected_disk, True)
|
|
elif unset_efi:
|
|
self.diskpart_flag(selected_disk, False)
|
|
else:
|
|
# Check erase
|
|
while True:
|
|
self.u.head("Erase {}".format(selected_disk.get("model","Unknown")))
|
|
print("")
|
|
print("{}. {} - {} ({})".format(
|
|
selected_disk.get("index",-1),
|
|
selected_disk.get("model","Unknown"),
|
|
self.get_size(selected_disk.get("size",-1)),
|
|
["Unknown","No Root Dir","Removable","Local","Network","Disc","RAM Disk"][selected_disk.get("type",0)]
|
|
))
|
|
print("")
|
|
print("If you continue - THIS DISK WILL BE ERASED")
|
|
print("ALL DATA WILL BE LOST AND ALL PARTITIONS WILL")
|
|
print("BE REMOVED!!!!!!!")
|
|
print("")
|
|
yn = self.u.grab("Continue? (y/n): ")
|
|
if yn.lower() == "n":
|
|
self.main()
|
|
return
|
|
if yn.lower() == "y":
|
|
break
|
|
# Got the OK to erase! Let's format a diskpart script!
|
|
self.diskpart_erase(selected_disk, use_gpt)
|
|
self.main()
|
|
|
|
w = WinUSB()
|
|
w.main()
|