diff --git a/OC/ACPI/SSDT-AWAC.aml b/OC/ACPI/SSDT-AWAC.aml
index 5189bf4..3698381 100644
Binary files a/OC/ACPI/SSDT-AWAC.aml and b/OC/ACPI/SSDT-AWAC.aml differ
diff --git a/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml b/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml
deleted file mode 100644
index fc27e3a..0000000
Binary files a/OC/ACPI/SSDT-EC-USBX-DESKTOP.aml and /dev/null differ
diff --git a/OC/ACPI/SSDT-EC.aml b/OC/ACPI/SSDT-EC.aml
new file mode 100644
index 0000000..877de34
Binary files /dev/null and b/OC/ACPI/SSDT-EC.aml differ
diff --git a/OC/ACPI/SSDT-GPRW.aml b/OC/ACPI/SSDT-GPRW.aml
new file mode 100644
index 0000000..0c51dd8
Binary files /dev/null and b/OC/ACPI/SSDT-GPRW.aml differ
diff --git a/OC/ACPI/SSDT-HPET.aml b/OC/ACPI/SSDT-HPET.aml
new file mode 100644
index 0000000..5a61ef9
Binary files /dev/null and b/OC/ACPI/SSDT-HPET.aml differ
diff --git a/OC/ACPI/SSDT-PLUG-ALT.aml b/OC/ACPI/SSDT-PLUG-ALT.aml
index a95705e..cb5e20e 100644
Binary files a/OC/ACPI/SSDT-PLUG-ALT.aml and b/OC/ACPI/SSDT-PLUG-ALT.aml differ
diff --git a/OC/ACPI/SSDT-RHUB.aml b/OC/ACPI/SSDT-RHUB.aml
deleted file mode 100644
index 61e45cc..0000000
Binary files a/OC/ACPI/SSDT-RHUB.aml and /dev/null differ
diff --git a/OC/ACPI/SSDT-SBUS-MCHC.aml b/OC/ACPI/SSDT-SBUS-MCHC.aml
new file mode 100644
index 0000000..edb8a41
Binary files /dev/null and b/OC/ACPI/SSDT-SBUS-MCHC.aml differ
diff --git a/OC/ACPI/SSDT-USBW.aml b/OC/ACPI/SSDT-USBW.aml
new file mode 100644
index 0000000..7171cef
Binary files /dev/null and b/OC/ACPI/SSDT-USBW.aml differ
diff --git a/OC/ACPI/SSDT-USBX.aml b/OC/ACPI/SSDT-USBX.aml
new file mode 100644
index 0000000..ca66962
Binary files /dev/null and b/OC/ACPI/SSDT-USBX.aml differ
diff --git a/OC/Kexts/USBMap.kext/Contents/Info.plist b/OC/Kexts/USBMap.kext/Contents/Info.plist
new file mode 100644
index 0000000..87952fd
--- /dev/null
+++ b/OC/Kexts/USBMap.kext/Contents/Info.plist
@@ -0,0 +1,204 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+ CFBundleGetInfoString
+ v1.0
+ CFBundleIdentifier
+ com.corpnewt.USBMap
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ USBMap
+ CFBundlePackageType
+ KEXT
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1.0
+ IOKitPersonalities
+
+ iMacPro1,1-XHCI
+
+ CFBundleIdentifier
+ com.apple.driver.AppleUSBHostMergeProperties
+ IOClass
+ AppleUSBHostMergeProperties
+ IOParentMatch
+
+ IOPropertyMatch
+
+ pcidebug
+ 0:20:0
+
+
+ IOProviderClass
+ AppleUSBXHCIPCI
+ IOProviderMergeProperties
+
+ kUSBMuxEnabled
+
+ port-count
+
+ DQAAAA==
+
+ ports
+
+ HS01
+
+ UsbConnector
+ 0
+ port
+
+ AQAAAA==
+
+
+ HS02
+
+ UsbConnector
+ 0
+ port
+
+ AgAAAA==
+
+
+ HS03
+
+ UsbConnector
+ 0
+ port
+
+ AwAAAA==
+
+
+ HS04
+
+ #port
+
+ BAAAAA==
+
+ UsbConnector
+ 3
+
+ HS05
+
+ UsbConnector
+ 255
+ port
+
+ BQAAAA==
+
+
+ HS06
+
+ UsbConnector
+ 255
+ port
+
+ BgAAAA==
+
+
+ HS07
+
+ UsbConnector
+ 0
+ port
+
+ BwAAAA==
+
+
+ HS08
+
+ UsbConnector
+ 0
+ port
+
+ CAAAAA==
+
+
+ HS09
+
+ #port
+
+ CQAAAA==
+
+ UsbConnector
+ 3
+
+ HS10
+
+ #port
+
+ CgAAAA==
+
+ UsbConnector
+ 3
+
+ HS11
+
+ #port
+
+ CwAAAA==
+
+ UsbConnector
+ 3
+
+ HS12
+
+ #port
+
+ DAAAAA==
+
+ UsbConnector
+ 3
+
+ SS01
+
+ UsbConnector
+ 3
+ port
+
+ DQAAAA==
+
+
+ SS02
+
+ #port
+
+ DgAAAA==
+
+ UsbConnector
+ 3
+
+ SS03
+
+ #port
+
+ DwAAAA==
+
+ UsbConnector
+ 3
+
+ SS04
+
+ #port
+
+ EAAAAA==
+
+ UsbConnector
+ 3
+
+
+
+ model
+ iMacPro1,1
+
+
+ OSBundleRequired
+ Root
+
+
diff --git a/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist b/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist
new file mode 100644
index 0000000..1cfc5d5
--- /dev/null
+++ b/OC/Kexts/USBWakeFixup.kext/Contents/Info.plist
@@ -0,0 +1,72 @@
+
+
+
+
+ BuildMachineOSBuild
+ 18G95
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ USBWakeFixup
+ CFBundleIdentifier
+ com.osy86.USBWakeFixup
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ USBWakeFixup
+ CFBundlePackageType
+ KEXT
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSupportedPlatforms
+
+ MacOSX
+
+ CFBundleVersion
+ 1
+ DTCompiler
+ com.apple.compilers.llvm.clang.1_0
+ DTPlatformBuild
+ 10G8
+ DTPlatformVersion
+ GM
+ DTSDKBuild
+ 18G74
+ DTSDKName
+ macosx10.14
+ DTXcode
+ 1030
+ DTXcodeBuild
+ 10G8
+ IOKitPersonalities
+
+ Fake XHCI
+
+ CFBundleIdentifier
+ com.osy86.USBWakeFixup
+ IOClass
+ USBWakeFixup
+ IONameMatch
+ PNP0D10
+ IOPropertyMatch
+
+ _UID
+ WAKE
+
+ IOProviderClass
+ IOACPIPlatformDevice
+
+
+ NSHumanReadableCopyright
+ Copyright © 2019 osy86. All rights reserved.
+ OSBundleLibraries
+
+ com.apple.iokit.IOACPIFamily
+ 1.0d1
+ com.apple.kpi.iokit
+ 7.0
+ com.apple.kpi.libkern
+ 8.0d0
+
+
+
diff --git a/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup b/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup
new file mode 100644
index 0000000..7191cd3
Binary files /dev/null and b/OC/Kexts/USBWakeFixup.kext/Contents/MacOS/USBWakeFixup differ
diff --git a/OC/config.plist b/OC/config.plist
index 20da3bf..d99d090 100644
--- a/OC/config.plist
+++ b/OC/config.plist
@@ -8,7 +8,7 @@
Comment
- Read the comment in dsl sample
+ SSDT-AWAC.aml
Enabled
Path
@@ -16,15 +16,31 @@
Comment
- Read the comment in dsl sample
+ SSDT-EC.aml
Enabled
Path
- SSDT-EC-USBX-DESKTOP.aml
+ SSDT-EC.aml
Comment
- Read the comment in dsl sample
+ SSDT-GPRW.aml
+ Enabled
+
+ Path
+ SSDT-GPRW.aml
+
+
+ Comment
+ SSDT-HPET.aml
+ Enabled
+
+ Path
+ SSDT-HPET.aml
+
+
+ Comment
+ SSDT-PLUG-ALT.aml
Enabled
Path
@@ -32,17 +48,214 @@
Comment
- Read the comment in dsl sample
+ SSDT-SBUS-MCHC.aml
Enabled
Path
- SSDT-RHUB.aml
+ SSDT-SBUS-MCHC.aml
+
+
+ Comment
+ SSDT-USBW.aml
+ Enabled
+
+ Path
+ SSDT-USBW.aml
+
+
+ Comment
+ SSDT-USBX.aml
+ Enabled
+
+ Path
+ SSDT-USBX.aml
Delete
Patch
-
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ HPET _STA to XSTA Rename
+ Count
+ 0
+ Enabled
+
+ Find
+ EV9TVEE=
+ Limit
+ 0
+ Mask
+
+ OemTableId
+ AAAAAA==
+ Replace
+ EVhTVEE=
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+ AAAAAA==
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ HPET _CRS to XCRS Rename
+ Count
+ 0
+ Enabled
+
+ Find
+ JV9DUlM=
+ Limit
+ 0
+ Mask
+
+ OemTableId
+ AAAAAA==
+ Replace
+ JVhDUlM=
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+ AAAAAA==
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ IPIC IRQ 2 Patch
+ Count
+ 0
+ Enabled
+
+ Find
+ IgQAeQA=
+ Limit
+ 0
+ Mask
+
+ OemTableId
+ AAAAAA==
+ Replace
+ IgAAeQA=
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+ AAAAAA==
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ RTC IRQ 8 Patch
+ Count
+ 0
+ Enabled
+
+ Find
+ IgABeQA=
+ Limit
+ 0
+ Mask
+
+ OemTableId
+ AAAAAA==
+ Replace
+ IgAAeQA=
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+ AAAAAA==
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ TIMR IRQ 0 Patch
+ Count
+ 0
+ Enabled
+
+ Find
+ IgEAeQA=
+ Limit
+ 0
+ Mask
+
+ OemTableId
+ AAAAAA==
+ Replace
+ IgAAeQA=
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+ AAAAAA==
+
+
+ Base
+
+ BaseSkip
+ 0
+ Comment
+ change Method(GPRW,2,N) to XPRW, pair with SSDT-GPRW.aml
+ Count
+ 0
+ Enabled
+
+ Find
+ R1BSVw==
+ Limit
+ 0
+ Mask
+
+ OemTableId
+
+ Replace
+ WFBSVw==
+ ReplaceMask
+
+ Skip
+ 0
+ TableLength
+ 0
+ TableSignature
+
+
+
Quirks
FadtEnableReset
@@ -113,23 +326,12 @@
Add
- # PciRoot(0x0)/Pci(0x1B,0x2)/Pci(0x0,0x0)
+ PciRoot(0x0)/Pci(0x1F,0x3)
- device-id
- 8hUAAA==
- device_type
- Ethernet Controller
+ layout-id
+ 66
model
- Intel(R) Ethernet Controller i225-LM
-
- # PciRoot(0x0)/Pci(0x1B,0x3)/Pci(0x0,0x0)
-
- device-id
- 8hUAAA==
- device_type
- Ethernet Controller
- model
- Intel(R) Ethernet Controller i225-LM
+ Realtek ALC897
Delete
@@ -337,6 +539,42 @@
PlistPath
Contents/Info.plist
+
+ Arch
+ x86_64
+ BundlePath
+ USBMap.kext
+ Comment
+
+ Enabled
+
+ ExecutablePath
+
+ MaxKernel
+
+ MinKernel
+
+ PlistPath
+ Contents/Info.plist
+
+
+ Arch
+ Any
+ BundlePath
+ USBWakeFixup.kext
+ Comment
+ USBWakeFixup.kext
+ Enabled
+
+ ExecutablePath
+ Contents/MacOS/USBWakeFixup
+ MaxKernel
+
+ MinKernel
+
+ PlistPath
+ Contents/Info.plist
+
Block
@@ -474,7 +712,7 @@
PickerAudioAssist
PickerMode
- External
+ Builtin
PickerVariant
Auto
PollAppleHotKeys
@@ -642,7 +880,7 @@
MaxBIOSVersion
ProcessorType
- 0
+ 3841
ROM
8LR5Nk5V
SpoofVendor
diff --git a/Utils/macrecovery/README.md b/Utils/macrecovery/README.md
deleted file mode 100644
index 4cf122b..0000000
--- a/Utils/macrecovery/README.md
+++ /dev/null
@@ -1,8 +0,0 @@
-## macrecovery
-
-macrecovery is a tool that helps to automate recovery interaction. It can be used to download diagnostics and recovery as well as analyse MLB.
-
-Requires python3 to run. Run with `-h` argument to see all available arguments.
-
-To create a disk image for a virtual machine installation use `build-image.sh`.
-
diff --git a/Utils/macrecovery/boards.json b/Utils/macrecovery/boards.json
deleted file mode 100644
index 489daa3..0000000
--- a/Utils/macrecovery/boards.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
- "Mac-EE2EBD4B90B839A8": "13.4",
- "Mac-BE0E8AC46FE800CC": "11.7.7",
- "Mac-9AE82516C7C6B903": "12.6.6",
- "Mac-942452F5819B1C1B": "10.13.6",
- "Mac-942C5DF58193131B": "10.13.6",
- "Mac-C08A6BB70A942AC2": "10.13.6",
- "Mac-742912EFDBEE19B3": "10.13.6",
- "Mac-66F35F19FE2A0D05": "10.15.7",
- "Mac-2E6FAB96566FE58C": "10.15.7",
- "Mac-35C1E88140C3E6CF": "11.7.7",
- "Mac-7DF21CB3ED6977E5": "11.7.7",
- "Mac-9F18E312C5C2BF0B": "12.6.6",
- "Mac-937CB26E2E02BB01": "12.6.6",
- "Mac-827FAC58A8FDFA22": "latest",
- "Mac-226CB3C6A851A671": "latest",
- "Mac-0CFF9C7C2B63DF8D": "latest",
- "Mac-C3EC7CD22292981F": "10.15.7",
- "Mac-AFD8A9D944EA4843": "10.15.7",
- "Mac-189A3D4F975D5FFC": "11.7.7",
- "Mac-3CBD00234E554E41": "11.7.7",
- "Mac-2BD1B31983FE1663": "11.7.7",
- "Mac-06F11FD93F0323C5": "12.6.6",
- "Mac-06F11F11946D27C5": "12.6.6",
- "Mac-E43C1C25D4880AD6": "12.6.6",
- "Mac-473D31EABEB93F9B": "12.6.6",
- "Mac-66E35819EE2D0D05": "12.6.6",
- "Mac-A5C67F76ED83108C": "12.6.6",
- "Mac-B4831CEBD52A0C4C": "13.4",
- "Mac-CAD6701F7CEA0921": "13.4",
- "Mac-551B86E5744E2388": "13.4",
- "Mac-937A206F2EE63C01": "latest",
- "Mac-827FB448E656EC26": "latest",
- "Mac-1E7E29AD0135F9BC": "latest",
- "Mac-53FDB3D8DB8CA971": "latest",
- "Mac-E1008331FDC96864": "latest",
- "Mac-5F9802EFE386AA28": "latest",
- "Mac-E7203C0F68AA0004": "latest",
- "Mac-A61BADE1FDAD7B05": "latest",
- "Mac-F22589C8": "10.13.6",
- "Mac-94245B3640C91C81": "10.13.6",
- "Mac-94245A3940C91C80": "10.13.6",
- "Mac-942459F5819B171B": "10.13.6",
- "Mac-4B7AC7E43945597E": "10.15.7",
- "Mac-6F01561E16C75D06": "10.15.7",
- "Mac-F60DEB81FF30ACF6": "12.6.6",
- "Mac-27AD2F918AE68F61": "latest",
- "Mac-F2208EC8": "10.13.6",
- "Mac-8ED6AF5B48C039E1": "10.13.6",
- "Mac-4BC72D62AD45599E": "10.13.6",
- "Mac-7BA5B2794B2CDB12": "10.13.6",
- "Mac-031AEE4D24BFF0B1": "10.15.7",
- "Mac-F65AE981FFA204ED": "10.15.7",
- "Mac-35C5E08120C7EEAF": "12.6.6",
- "Mac-7BA5B2DFE22DDD8C": "latest",
- "Mac-942B5BF58194151B": "10.13.6",
- "Mac-942B59F58194171B": "10.13.6",
- "Mac-00BE6ED71E35EB86": "10.15.7",
- "Mac-FC02E91DDD3FA6A4": "10.15.7",
- "Mac-7DF2A3B5E5D671ED": "10.15.7",
- "Mac-031B6874CF7F642A": "10.15.7",
- "Mac-27ADBB7B4CEE8E61": "10.15.7",
- "Mac-77EB7D7DAF985301": "10.15.7",
- "Mac-81E3E92DD6088272": "11.7.7",
- "Mac-42FD25EABCABB274": "11.7.7",
- "Mac-A369DDC4E67F1C45": "12.6.6",
- "Mac-FFE5EF870D7BA81A": "12.6.6",
- "Mac-DB15BD556843C820": "12.6.6",
- "Mac-65CE76090165799A": "12.6.6",
- "Mac-B809C3757DA9BB8D": "12.6.6",
- "Mac-4B682C642B45593E": "13.4",
- "Mac-77F17D7DA9285301": "13.4",
- "Mac-BE088AF8C5EB4FA2": "13.4",
- "Mac-AA95B1DDAB278B95": "latest",
- "Mac-63001698E7A34814": "latest",
- "Mac-CFF7D910A743CAAF": "latest",
- "Mac-AF89B6D9451A490B": "latest",
- "Mac-7BA5B2D9E42DDD94": "latest"
-}
\ No newline at end of file
diff --git a/Utils/macrecovery/build-image.sh b/Utils/macrecovery/build-image.sh
deleted file mode 100755
index 8dc7107..0000000
--- a/Utils/macrecovery/build-image.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash -e
-
-rm -rf Recovery.RO.dmg Recovery.RO.raw Recovery.dmg.sparseimage
-hdiutil create -size 800m -layout "UNIVERSAL HD" -type SPARSE -o Recovery.dmg
-newDevice=$(hdiutil attach -nomount Recovery.dmg.sparseimage | head -n 1 | awk '{print $1}')
-echo newdevice "$newDevice"
-diskutil partitionDisk "${newDevice}" 1 MBR fat32 RECOVERY R
-N=$(echo "$newDevice" | tr -dc '0-9')
-diskutil mount disk"${N}"s1
-MOUNT="$(diskutil info disk"${N}"s1 | sed -n 's/.*Mount Point: *//p')"
-mkdir -p "$MOUNT/com.apple.recovery.boot"
-cp ./*.dmg ./*.chunklist "$MOUNT/com.apple.recovery.boot/"
-diskutil umount disk"${N}"s1
-hdiutil detach "$newDevice"
-hdiutil convert -format UDZO Recovery.dmg.sparseimage -o Recovery.RO.dmg
-rm Recovery.dmg.sparseimage
-qemu-img convert -f dmg -O raw Recovery.RO.dmg Recovery.raw
-rm Recovery.RO.dmg
diff --git a/Utils/macrecovery/download-macOS-Big-Sur.cmd b/Utils/macrecovery/download-macOS-Big-Sur.cmd
deleted file mode 100755
index 20c9bb2..0000000
--- a/Utils/macrecovery/download-macOS-Big-Sur.cmd
+++ /dev/null
@@ -1,11 +0,0 @@
-@echo off
-
-rem Download imagem Recovery macOS Big Sur
-rem
-rem Gabriel Luchina
-rem Universo Hackintosh
-rem https://universohackintosh.com.br
-
-cls
-
-python ./macrecovery.py -b Mac-42FD25EABCABB274 -m 00000000000000000 download
diff --git a/Utils/macrecovery/download-macOS-Catalina.cmd b/Utils/macrecovery/download-macOS-Catalina.cmd
deleted file mode 100755
index 17c7679..0000000
--- a/Utils/macrecovery/download-macOS-Catalina.cmd
+++ /dev/null
@@ -1,11 +0,0 @@
-@echo off
-
-rem Download imagem Recovery macOS Catalina
-rem
-rem Gabriel Luchina
-rem Universo Hackintosh
-rem https://universohackintosh.com.br
-
-cls
-
-python ./macrecovery.py -b Mac-00BE6ED71E35EB86 -m 00000000000000000 download
diff --git a/Utils/macrecovery/download-macOS-Monterey.cmd b/Utils/macrecovery/download-macOS-Monterey.cmd
deleted file mode 100755
index fc3442b..0000000
--- a/Utils/macrecovery/download-macOS-Monterey.cmd
+++ /dev/null
@@ -1,11 +0,0 @@
-@echo off
-
-rem Download imagem Recovery macOS Monterey
-rem
-rem Gabriel Luchina
-rem Universo Hackintosh
-rem https://universohackintosh.com.br
-
-cls
-
-python ./macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000000000 download
diff --git a/Utils/macrecovery/download-macOS-Ventura.cmd b/Utils/macrecovery/download-macOS-Ventura.cmd
deleted file mode 100755
index cf17110..0000000
--- a/Utils/macrecovery/download-macOS-Ventura.cmd
+++ /dev/null
@@ -1,11 +0,0 @@
-@echo off
-
-rem Download imagem Recovery macOS Ventura
-rem
-rem Gabriel Luchina
-rem Universo Hackintosh
-rem https://universohackintosh.com.br
-
-cls
-
-python ./macrecovery.py -b Mac-B4831CEBD52A0C4C -m 00000000000000000 download
diff --git a/Utils/macrecovery/macrecovery.py b/Utils/macrecovery/macrecovery.py
deleted file mode 100755
index 76a60aa..0000000
--- a/Utils/macrecovery/macrecovery.py
+++ /dev/null
@@ -1,502 +0,0 @@
-#!/usr/bin/env python3
-
-"""
-Gather recovery information for Macs.
-
-Copyright (c) 2019, vit9696
-"""
-
-import argparse
-import binascii
-import hashlib
-import json
-import linecache
-import os
-import random
-import struct
-import sys
-
-try:
- from urllib.request import Request, HTTPError, urlopen
- from urllib.parse import urlparse
-except ImportError:
- from urllib2 import Request, HTTPError, urlopen
- from urlparse import urlparse
-
-SELF_DIR = os.path.dirname(os.path.realpath(__file__))
-
-RECENT_MAC = 'Mac-7BA5B2D9E42DDD94'
-MLB_ZERO = '00000000000000000'
-MLB_VALID = 'C02749200YGJ803AX'
-MLB_PRODUCT = '00000000000J80300'
-
-TYPE_SID = 16
-TYPE_K = 64
-TYPE_FG = 64
-
-INFO_PRODUCT = 'AP'
-INFO_IMAGE_LINK = 'AU'
-INFO_IMAGE_HASH = 'AH'
-INFO_IMAGE_SESS = 'AT'
-INFO_SIGN_LINK = 'CU'
-INFO_SIGN_HASH = 'CH'
-INFO_SIGN_SESS = 'CT'
-INFO_REQURED = [INFO_PRODUCT, INFO_IMAGE_LINK, INFO_IMAGE_HASH, INFO_IMAGE_SESS, INFO_SIGN_LINK, INFO_SIGN_HASH, INFO_SIGN_SESS]
-
-
-def run_query(url, headers, post=None, raw=False):
- if post is not None:
- data = '\n'.join([entry + '=' + post[entry] for entry in post])
- if sys.version_info[0] >= 3:
- data = data.encode('utf-8')
- else:
- data = None
- req = Request(url=url, headers=headers, data=data)
- try:
- response = urlopen(req)
- if raw:
- return response
- return dict(response.info()), response.read()
- except HTTPError as e:
- print(f'ERROR: "{e}" when connecting to {url}')
- sys.exit(1)
-
-
-def generate_id(id_type, id_value=None):
- valid_chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']
- return ''.join(random.choice(valid_chars) for i in range(id_type)) if not id_value else id_value
-
-
-def product_mlb(mlb):
- return '00000000000' + mlb[11] + mlb[12] + mlb[13] + mlb[14] + '00'
-
-
-def mlb_from_eeee(eeee):
- if len(eeee) != 4:
- print('ERROR: Invalid EEEE code length!')
- sys.exit(1)
-
- return f'00000000000{eeee}00'
-
-
-def int_from_unsigned_bytes(byte_list, byteorder):
- if byteorder == 'little':
- byte_list = byte_list[::-1]
- encoded = binascii.hexlify(byte_list)
- return int(encoded, 16)
-
-
-# zhangyoufu https://gist.github.com/MCJack123/943eaca762730ca4b7ae460b731b68e7#gistcomment-3061078 2021-10-08
-Apple_EFI_ROM_public_key_1 = 0xC3E748CAD9CD384329E10E25A91E43E1A762FF529ADE578C935BDDF9B13F2179D4855E6FC89E9E29CA12517D17DFA1EDCE0BEBF0EA7B461FFE61D94E2BDF72C196F89ACD3536B644064014DAE25A15DB6BB0852ECBD120916318D1CCDEA3C84C92ED743FC176D0BACA920D3FCF3158AFF731F88CE0623182A8ED67E650515F75745909F07D415F55FC15A35654D118C55A462D37A3ACDA08612F3F3F6571761EFCCBCC299AEE99B3A4FD6212CCFFF5EF37A2C334E871191F7E1C31960E010A54E86FA3F62E6D6905E1CD57732410A3EB0C6B4DEFDABE9F59BF1618758C751CD56CEF851D1C0EAA1C558E37AC108DA9089863D20E2E7E4BF475EC66FE6B3EFDCF
-
-ChunkListHeader = struct.Struct('<4sIBBBxQQQ')
-assert ChunkListHeader.size == 0x24
-
-Chunk = struct.Struct(' 0
- assert chunk_offset == 0x24
- assert signature_offset == chunk_offset + Chunk.size * chunk_count
- for _ in range(chunk_count):
- data = f.read(Chunk.size)
- hash_ctx.update(data)
- chunk_size, chunk_sha256 = Chunk.unpack(data)
- yield chunk_size, chunk_sha256
- digest = hash_ctx.digest()
- if signature_method == 1:
- data = f.read(256)
- assert len(data) == 256
- signature = int_from_unsigned_bytes(data, 'little')
- plaintext = 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004200000000000000000000000000000000000000000000000000000000000000000 | int_from_unsigned_bytes(digest, 'big')
- assert pow(signature, 0x10001, Apple_EFI_ROM_public_key_1) == plaintext
- elif signature_method == 2:
- data = f.read(32)
- assert data == digest
- raise RuntimeError('Chunklist missing digital signature')
- else:
- raise NotImplementedError
- assert f.read(1) == b''
-
-
-def get_session(args):
- headers = {
- 'Host': 'osrecovery.apple.com',
- 'Connection': 'close',
- 'User-Agent': 'InternetRecovery/1.0',
- }
-
- headers, _ = run_query('http://osrecovery.apple.com/', headers)
-
- if args.verbose:
- print('Session headers:')
- for header in headers:
- print(f'{header}: {headers[header]}')
-
- for header in headers:
- if header.lower() == 'set-cookie':
- cookies = headers[header].split('; ')
- for cookie in cookies:
- return cookie if cookie.startswith('session=') else ...
-
- raise RuntimeError('No session in headers ' + str(headers))
-
-
-def get_image_info(session, bid, mlb=MLB_ZERO, diag=False, os_type='default', cid=None):
- headers = {
- 'Host': 'osrecovery.apple.com',
- 'Connection': 'close',
- 'User-Agent': 'InternetRecovery/1.0',
- 'Cookie': session,
- 'Content-Type': 'text/plain',
- }
-
- post = {
- 'cid': generate_id(TYPE_SID, cid),
- 'sn': mlb,
- 'bid': bid,
- 'k': generate_id(TYPE_K),
- 'fg': generate_id(TYPE_FG)
- }
-
- if diag:
- url = 'http://osrecovery.apple.com/InstallationPayload/Diagnostics'
- else:
- url = 'http://osrecovery.apple.com/InstallationPayload/RecoveryImage'
- post['os'] = os_type
-
- headers, output = run_query(url, headers, post)
-
- output = output.decode('utf-8')
- info = {}
- for line in output.split('\n'):
- try:
- key, value = line.split(': ')
- info[key] = value
- except Exception:
- continue
-
- for k in INFO_REQURED:
- if k not in info:
- raise RuntimeError(f'Missing key {k}')
-
- return info
-
-
-def save_image(url, sess, filename='', directory=''):
- purl = urlparse(url)
- headers = {
- 'Host': purl.hostname,
- 'Connection': 'close',
- 'User-Agent': 'InternetRecovery/1.0',
- 'Cookie': '='.join(['AssetToken', sess])
- }
-
- if not os.path.exists(directory):
- os.mkdir(directory)
-
- if filename == '':
- filename = os.path.basename(purl.path)
- if filename.find('/') >= 0 or filename == '':
- raise RuntimeError('Invalid save path ' + filename)
-
- print(f'Saving {url} to {directory}/{filename}...')
-
- with open(os.path.join(directory, filename), 'wb') as fh:
- response = run_query(url, headers, raw=True)
- size = 0
- while True:
- chunk = response.read(2**20)
- if not chunk:
- break
- fh.write(chunk)
- size += len(chunk)
- print(f'\r{size / (2**20)} MBs downloaded...', end='')
- sys.stdout.flush()
- print('\rDownload complete!\t\t\t\t\t')
-
- return os.path.join(directory, os.path.basename(filename))
-
-
-def verify_image(dmgpath, cnkpath):
- print('Verifying image with chunklist...')
-
- with open(dmgpath, 'rb') as dmgf:
- cnkcount = 0
- for cnksize, cnkhash in verify_chunklist(cnkpath):
- cnkcount += 1
- print(f'\rChunk {cnkcount} ({cnksize} bytes)', end='')
- sys.stdout.flush()
- cnk = dmgf.read(cnksize)
- if len(cnk) != cnksize:
- raise RuntimeError(f'Invalid chunk {cnkcount} size: expected {cnksize}, read {len(cnk)}')
- if hashlib.sha256(cnk).digest() != cnkhash:
- raise RuntimeError(f'Invalid chunk {cnkcount}: hash mismatch')
- if dmgf.read(1) != b'':
- raise RuntimeError('Invalid image: larger than chunklist')
- print('\rImage verification complete!\t\t\t\t\t')
-
-
-def action_download(args):
- """
- Reference information for queries:
-
- Recovery latest:
- cid=3076CE439155BA14
- sn=...
- bid=Mac-E43C1C25D4880AD6
- k=4BE523BB136EB12B1758C70DB43BDD485EBCB6A457854245F9E9FF0587FB790C
- os=latest
- fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC
-
- Recovery default:
- cid=4A35CB95FF396EE7
- sn=...
- bid=Mac-E43C1C25D4880AD6
- k=0A385E6FFC3DDD990A8A1F4EC8B98C92CA5E19C9FF1DD26508C54936D8523121
- os=default
- fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC
-
- Diagnostics:
- cid=050C59B51497CEC8
- sn=...
- bid=Mac-E43C1C25D4880AD6
- k=37D42A8282FE04A12A7D946304F403E56A2155B9622B385F3EB959A2FBAB8C93
- fg=B2E6AA07DB9088BE5BDB38DB2EA824FDDFB6C3AC5272203B32D89F9D8E3528DC
- """
-
- session = get_session(args)
- info = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=args.diagnostics, os_type=args.os_type)
- if args.verbose:
- print(info)
- print(f'Downloading {info[INFO_PRODUCT]}...')
- dmgname = '' if args.basename == '' else args.basename + '.dmg'
- dmgpath = save_image(info[INFO_IMAGE_LINK], info[INFO_IMAGE_SESS], dmgname, args.outdir)
- cnkname = '' if args.basename == '' else args.basename + '.chunklist'
- cnkpath = save_image(info[INFO_SIGN_LINK], info[INFO_SIGN_SESS], cnkname, args.outdir)
- try:
- verify_image(dmgpath, cnkpath)
- return 0
- except Exception as err:
- if isinstance(err, AssertionError) and str(err) == '':
- try:
- tb = sys.exc_info()[2]
- while tb.tb_next:
- tb = tb.tb_next
- err = linecache.getline(tb.tb_frame.f_code.co_filename, tb.tb_lineno, tb.tb_frame.f_globals).strip()
- except Exception:
- err = "Invalid chunklist"
- print(f'\rImage verification failed. ({err})')
- return 1
-
-
-def action_selfcheck(args):
- """
- Sanity check server logic for recovery:
-
- if not valid(bid):
- return error()
- ppp = get_ppp(sn)
- if not valid(ppp):
- return latest_recovery(bid = bid) # Returns newest for bid.
- if valid(sn):
- if os == 'default':
- return default_recovery(sn = sn, ppp = ppp) # Returns oldest for sn.
- else:
- return latest_recovery(sn = sn, ppp = ppp) # Returns newest for sn.
- return default_recovery(ppp = ppp) # Returns oldest.
- """
-
- session = get_session(args)
- valid_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_VALID, diag=False, os_type='default')
- valid_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_VALID, diag=False, os_type='latest')
- product_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_PRODUCT, diag=False, os_type='default')
- product_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_PRODUCT, diag=False, os_type='latest')
- generic_default = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='default')
- generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest')
-
- if args.verbose:
- print(valid_default)
- print(valid_latest)
- print(product_default)
- print(product_latest)
- print(generic_default)
- print(generic_latest)
-
- if valid_default[INFO_PRODUCT] == valid_latest[INFO_PRODUCT]:
- # Valid MLB must give different default and latest if this is not a too new product.
- print(f'ERROR: Cannot determine any previous product, got {valid_default[INFO_PRODUCT]}')
- return 1
-
- if product_default[INFO_PRODUCT] != product_latest[INFO_PRODUCT]:
- # Product-only MLB must give the same value for default and latest.
- print(f'ERROR: Latest and default do not match for product MLB, got {product_default[INFO_PRODUCT]} and {product_latest[INFO_PRODUCT]}')
- return 1
-
- if generic_default[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]:
- # Zero MLB always give the same value for default and latest.
- print(f'ERROR: Generic MLB gives different product, got {generic_default[INFO_PRODUCT]} and {generic_latest[INFO_PRODUCT]}')
- return 1
-
- if valid_latest[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]:
- # Valid MLB must always equal generic MLB.
- print(f'ERROR: Cannot determine unified latest product, got {valid_latest[INFO_PRODUCT]} and {generic_latest[INFO_PRODUCT]}')
- return 1
-
- if product_default[INFO_PRODUCT] != valid_default[INFO_PRODUCT]:
- # Product-only MLB can give the same value with valid default MLB.
- # This is not an error for all models, but for our chosen code it is.
- print('ERROR: Valid and product MLB give mismatch, got {product_default[INFO_PRODUCT]} and {valid_default[INFO_PRODUCT]}')
- return 1
-
- print('SUCCESS: Found no discrepancies with MLB validation algorithm!')
- return 0
-
-
-def action_verify(args):
- """
- Try to verify MLB serial number.
- """
- session = get_session(args)
- generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest')
- uvalid_default = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=False, os_type='default')
- uvalid_latest = get_image_info(session, bid=args.board_id, mlb=args.mlb, diag=False, os_type='latest')
- uproduct_default = get_image_info(session, bid=args.board_id, mlb=product_mlb(args.mlb), diag=False, os_type='default')
-
- if args.verbose:
- print(generic_latest)
- print(uvalid_default)
- print(uvalid_latest)
- print(uproduct_default)
-
- # Verify our MLB number.
- if uvalid_default[INFO_PRODUCT] != uvalid_latest[INFO_PRODUCT]:
- print(f'SUCCESS: {args.mlb} MLB looks valid and supported!' if uvalid_latest[INFO_PRODUCT] == generic_latest[INFO_PRODUCT] else f'SUCCESS: {args.mlb} MLB looks valid, but probably unsupported!')
- return 0
-
- print('UNKNOWN: Run selfcheck, check your board-id, or try again later!')
-
- # Here we have matching default and latest products. This can only be true for very
- # new models. These models get either latest or special builds.
- if uvalid_default[INFO_PRODUCT] == generic_latest[INFO_PRODUCT]:
- print(f'UNKNOWN: {args.mlb} MLB can be valid if very new!')
- return 0
- if uproduct_default[INFO_PRODUCT] != uvalid_default[INFO_PRODUCT]:
- print(f'UNKNOWN: {args.mlb} MLB looks invalid, other models use product {uproduct_default[INFO_PRODUCT]} instead of {uvalid_default[INFO_PRODUCT]}!')
- return 0
- print(f'UNKNOWN: {args.mlb} MLB can be valid if very new and using special builds!')
- return 0
-
-
-def action_guess(args):
- """
- Attempt to guess which model does this MLB belong.
- """
-
- mlb = args.mlb
- anon = mlb.startswith('000')
-
- with open(args.board_db, 'r', encoding='utf-8') as fh:
- db = json.load(fh)
-
- supported = {}
-
- session = get_session(args)
-
- generic_latest = get_image_info(session, bid=RECENT_MAC, mlb=MLB_ZERO, diag=False, os_type='latest')
-
- for model in db:
- try:
- if anon:
- # For anonymous lookup check when given model does not match latest.
- model_latest = get_image_info(session, bid=model, mlb=MLB_ZERO, diag=False, os_type='latest')
-
- if model_latest[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]:
- if db[model] == 'current':
- print(f'WARN: Skipped {model} due to using latest product {model_latest[INFO_PRODUCT]} instead of {generic_latest[INFO_PRODUCT]}')
- continue
-
- user_default = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='default')
-
- if user_default[INFO_PRODUCT] != generic_latest[INFO_PRODUCT]:
- supported[model] = [db[model], user_default[INFO_PRODUCT], generic_latest[INFO_PRODUCT]]
- else:
- # For normal lookup check when given model has mismatching normal and latest.
- user_latest = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='latest')
-
- user_default = get_image_info(session, bid=model, mlb=mlb, diag=False, os_type='default')
-
- if user_latest[INFO_PRODUCT] != user_default[INFO_PRODUCT]:
- supported[model] = [db[model], user_default[INFO_PRODUCT], user_latest[INFO_PRODUCT]]
-
- except Exception as e:
- print(f'WARN: Failed to check {model}, exception: {e}')
-
- if len(supported) > 0:
- print(f'SUCCESS: MLB {mlb} looks supported for:')
- for model in supported.items():
- print(f'- {model}, up to {supported[model][0]}, default: {supported[model][1]}, latest: {supported[model][2]}')
- return 0
-
- print(f'UNKNOWN: Failed to determine supported models for MLB {mlb}!')
- return None
-
-
-def main():
- parser = argparse.ArgumentParser(description='Gather recovery information for Macs')
- parser.add_argument('action', choices=['download', 'selfcheck', 'verify', 'guess'],
- help='Action to perform: "download" - performs recovery downloading,'
- ' "selfcheck" checks whether MLB serial validation is possible, "verify" performs'
- ' MLB serial verification, "guess" tries to find suitable mac model for MLB.')
- parser.add_argument('-o', '--outdir', type=str, default='com.apple.recovery.boot',
- help='customise output directory for downloading, defaults to com.apple.recovery.boot')
- parser.add_argument('-n', '--basename', type=str, default='',
- help='customise base name for downloading, defaults to remote name')
- parser.add_argument('-b', '--board-id', type=str, default=RECENT_MAC,
- help=f'use specified board identifier for downloading, defaults to {RECENT_MAC}')
- parser.add_argument('-m', '--mlb', type=str, default=MLB_ZERO,
- help=f'use specified logic board serial for downloading, defaults to {MLB_ZERO}')
- parser.add_argument('-e', '--code', type=str, default='',
- help='generate product logic board serial with specified product EEEE code')
- parser.add_argument('-os', '--os-type', type=str, default='default', choices=['default', 'latest'],
- help=f'use specified os type, defaults to default {MLB_ZERO}')
- parser.add_argument('-diag', '--diagnostics', action='store_true', help='download diagnostics image')
- parser.add_argument('-v', '--verbose', action='store_true', help='print debug information')
- parser.add_argument('-db', '--board-db', type=str, default=os.path.join(SELF_DIR, 'boards.json'),
- help='use custom board list for checking, defaults to boards.json')
-
- args = parser.parse_args()
-
- if args.code != '':
- args.mlb = mlb_from_eeee(args.code)
-
- if len(args.mlb) != 17:
- print('ERROR: Cannot use MLBs in non 17 character format!')
- sys.exit(1)
-
- if args.action == 'download':
- return action_download(args)
- if args.action == 'selfcheck':
- return action_selfcheck(args)
- if args.action == 'verify':
- return action_verify(args)
- if args.action == 'guess':
- return action_guess(args)
-
- assert False
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/Utils/macrecovery/recovery_urls.txt b/Utils/macrecovery/recovery_urls.txt
deleted file mode 100644
index ca233f3..0000000
--- a/Utils/macrecovery/recovery_urls.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-# Lion (10.7):
-python macrecovery.py -b Mac-2E6FAB96566FE58C -m 00000000000F25Y00 download
-python macrecovery.py -b Mac-C3EC7CD22292981F -m 00000000000F0HM00 download
-
-# Mountain Lion (10.8):
-python macrecovery.py -b Mac-7DF2A3B5E5D671ED -m 00000000000F65100 download
-
-# Mavericks (10.9):
-python macrecovery.py -b Mac-F60DEB81FF30ACF6 -m 00000000000FNN100 download
-
-# Yosemite (10.10):
-python macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000GDVW00 download
-
-# El Capitan (10.11):
-python macrecovery.py -b Mac-FFE5EF870D7BA81A -m 00000000000GQRX00 download
-
-# Sierra (10.12):
-python macrecovery.py -b Mac-77F17D7DA9285301 -m 00000000000J0DX00 download
-
-# High Sierra (10.13)
-python macrecovery.py -b Mac-7BA5B2D9E42DDD94 -m 00000000000J80300 download
-python macrecovery.py -b Mac-BE088AF8C5EB4FA2 -m 00000000000J80300 download
-
-# Mojave (10.14)
-python macrecovery.py -b Mac-7BA5B2DFE22DDD8C -m 00000000000KXPG00 download
-
-# Catalina (10.15)
-python macrecovery.py -b Mac-00BE6ED71E35EB86 -m 00000000000000000 download
-
-# Big Sur (11)
-python macrecovery.py -b Mac-42FD25EABCABB274 -m 00000000000000000 download
-
-# Monterey (12)
-python macrecovery.py -b Mac-E43C1C25D4880AD6 -m 00000000000000000 download
-
-# Latest version
-# ie. Ventura (13)
-python macrecovery.py -b Mac-B4831CEBD52A0C4C -m 00000000000000000 download
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist b/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist
deleted file mode 100644
index 9c7abaa..0000000
--- a/Utils/mountefi/Mount EFI.workflow/Contents/Info.plist
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- NSServices
-
-
- NSBackgroundColorName
- background
- NSIconName
- NSTouchBarTransferDownload
- NSMenuItem
-
- default
- Mount EFI
-
- NSMessage
- runWorkflowAsService
- NSSendFileTypes
-
- public.folder
-
-
-
-
-
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png b/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png
deleted file mode 100644
index 7fd8cb5..0000000
Binary files a/Utils/mountefi/Mount EFI.workflow/Contents/QuickLook/Thumbnail.png and /dev/null differ
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py
deleted file mode 100755
index 3a8d621..0000000
--- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/disk.py
+++ /dev/null
@@ -1,411 +0,0 @@
-import os, sys
-sys.path.append(os.path.abspath(os.path.dirname(os.path.realpath(__file__))))
-import run, plist
-
-class Disk:
- def __init__(self):
- self.r = run.Run()
- self.diskdump = self.check_diskdump()
- self.full_os_version = self.r.run({"args":["sw_vers", "-productVersion"]})[0]
- if len(self.full_os_version.split(".")) < 3:
- # Ensure the format is XX.YY.ZZ
- self.full_os_version += ".0"
- self.os_version = ".".join(self.full_os_version.split(".")[:2])
- self.sudo_mount_version = "10.13.6"
- self.efi_guids = ["C12A7328-F81F-11D2-BA4B-00A0C93EC93B"]
- self.disks = self.get_disks()
-
- def check_diskdump(self):
- ddpath = os.path.join(os.path.dirname(os.path.realpath(__file__)),"diskdump")
- if not os.path.exists(ddpath):
- raise FileNotFoundError("Could not locate diskdump")
- if "com.apple.quarantine" in self.r.run({"args":["xattr",ddpath]})[0]:
- self.r.run({"args":["xattr","-d","com.apple.quarantine",ddpath]})
- return ddpath
-
- def update(self):
- # Refresh our disk list
- self.disks = self.get_disks()
- return self.disks
-
- def get_disks(self):
- # Check for our binary - and ensure it's setup to run
- ddpath = os.path.join(os.path.dirname(os.path.realpath(__file__)),"diskdump")
- if not os.path.exists(ddpath): return {}
- # Get our "diskutil list" and diskdump info. Run diskutil list first
- # as it takes longer - but will stall while waiting for disks to appear,
- # meaning our diskdump output will be better reflected.
- diskutil_list = self.r.run({"args":["diskutil","list"]})[0]
- diskstring = self.r.run({"args":[ddpath]})[0]
- if not diskstring: return {}
- diskdump = plist.loads(diskstring)
- last_disk = None
- for line in diskutil_list.split("\n"):
- if line.startswith("/dev/disk"):
- last_disk = line.split()[0].split("/")[-1]
- elif not last_disk:
- continue
- elif line.strip().startswith("Logical Volume on"):
- # Core Storage
- ps = line.split("Logical Volume on")[1].strip().split(", ")
- disk = self.get_disk(last_disk,disk_dict=diskdump)
- if disk: # Update parent disk
- disk["container"] = True
- disk["core_storage"] = True
- disk["physical_stores"] = ps
- # Save a reference to the physical stores
- for s in ps:
- store = self.get_disk(s,disk_dict=diskdump)
- if store:
- store["container_for"] = last_disk
- store["core_storage_container_for"] = last_disk
- elif line.strip().startswith("Physical Store"):
- # APFS
- ps = line.split("Physical Store")[1].strip().split(", ")
- disk = self.get_disk(last_disk,disk_dict=diskdump)
- if disk: # Update parent disk
- disk["container"] = True
- disk["apfs"] = True
- disk["physical_stores"] = ps
- # Save a reference to the physical stores
- for s in ps:
- store = self.get_disk(s,disk_dict=diskdump)
- if store:
- store["container_for"] = last_disk
- store["apfs_container_for"] = last_disk
- return diskdump
-
- def get_identifier(self, disk = None, disk_dict = None):
- # Should be able to take a mount point, disk name, or disk identifier,
- # and return the disk's identifier
- if isinstance(disk,dict): disk = disk.get("DAMediaBSDName")
- if not disk: return
- disk_dict = disk_dict or self.disks # Normalize the dict
- disk = disk[6:] if disk.lower().startswith("/dev/rdisk") else disk[5:] if disk.lower().startswith("/dev/disk") else disk
- if disk.lower() in disk_dict.get("AllDisks",[]): return disk
- for d in disk_dict.get("AllDisksAndPartitions", []):
- # Check the parent disk
- if any((disk.lower()==d.get(x,"").lower() for x in ("DAMediaBSDName","DAVolumeName","DAVolumeUUID","DAMediaUUID","DAVolumePath"))):
- return d.get("DAMediaBSDName")
- # Check the partitions
- for p in d.get("Partitions", []):
- if any((disk.lower()==p.get(x,"").lower() for x in ("DAMediaBSDName","DAVolumeName","DAVolumeUUID","DAMediaUUID","DAVolumePath"))):
- return p.get("DAMediaBSDName")
- # At this point, we didn't find it
- return None
-
- def get_parent(self, disk = None, disk_dict = None):
- # For backward compatibility with the old disk.py approach
- return self.get_physical_parent_identifiers(disk,disk_dict=disk_dict)
-
- def get_parent_identifier(self, disk = None, disk_dict = None):
- # Resolves the passed disk value and returns the parent disk/container.
- # i.e. Passing disk5s2s1 would return disk5
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- return "disk"+disk.lower().split("disk")[1].split("s")[0]
-
- def get_physical_parent_identifier(self, disk = None, disk_dict = None):
- # Returns the first hit from get_physical_parent_identifiers()
- return next(iter(self.get_physical_parent_identifiers(disk, disk_dict=disk_dict) or []), None)
-
- def get_physical_parent_identifiers(self, disk = None, disk_dict = None):
- # Resolves the passed disk to the physical parent disk identifiers. Useful for APFS
- # and Core Storage volumes which are logical - and can span multiple disks.
- # If you have an APFS container on disk4 and its Physical Store lists
- # disk2s2, disk3s2 - this would return [disk2, disk3]
- return [self.get_identifier(x,disk_dict=disk_dict) for x in self.get_physical_parent_disks(disk,disk_dict=disk_dict)]
-
- def get_physical_parent_disks(self, disk = None, disk_dict = None):
- # Resolves the passed disk to the physical parent disk dicts. Useful for APFS
- # and Core Storage volumes which are logcial and can span multiple physical
- # disks. If you have an APFS container on disk4 and its Physical Store is on
- # disk2s2 and disk3s2 - this would return the disk dicts for disk2 and disk3.
- parent = self.get_parent_disk(disk, disk_dict=disk_dict)
- if not parent: return []
- if not "physical_stores" in parent: return [parent]
- return [self.get_parent_disk(x,disk_dict=disk_dict) for x in parent.get("physical_stores",[])]
-
- def get_parent_disk(self, disk = None, disk_dict = None):
- # Returns the dict info for the parent of the passed mount point, name, identifier, etc
- return self.get_disk(self.get_parent_identifier(disk,disk_dict=disk_dict),disk_dict=disk_dict)
-
- def get_disk(self, disk = None, disk_dict = None):
- # Returns the dict info for the passed mount point, name, identifier, etc
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- parent = self.get_parent_identifier(disk,disk_dict=disk_dict)
- # Walk AllDisksAndPartitions, and return the first hit
- for d in (disk_dict or self.disks).get("AllDisksAndPartitions",[]):
- d_ident = d.get("DAMediaBSDName")
- if d_ident == disk:
- return d # Got the disk
- elif d_ident == parent:
- # Got the parent - iterate the partitions
- return next((p for p in d.get("Partitions",[]) if p.get("DAMediaBSDName")==disk),None)
- return None # Didn't find it
-
- def get_efis(self, disk = None, disk_dict = None):
- # Returns the identifiers for any EFI partitions attached to the
- # parent disk(s) of the passed disk
- efis = []
- for parent in self.get_physical_parent_identifiers(disk,disk_dict=disk_dict):
- parent_dict = self.get_disk(parent,disk_dict=disk_dict)
- if not parent_dict: continue
- for part in parent_dict.get("Partitions",[]):
- # Use the GUID instead of media name - as that can vary
- if part.get("DAMediaContent","").upper() in self.efi_guids:
- efis.append(part["DAMediaBSDName"])
- # Normalize case for the DAMediaName;
- # macOS disks: "EFI System Partition", Windows disks: "EFI system partition"
- # Maybe use this approach as a fallback at some point - but for now, just use the GUID
- # if part.get("DAMediaName").lower() == "efi system partition":
- # efis.append(part["DAMediaBSDName"])
- return efis
-
- def get_efi(self, disk = None, disk_dict = None):
- # Returns the identifier for the first EFI partition found for
- # the passed disk
- return next(iter(self.get_efis(disk,disk_dict=disk_dict) or []), None)
-
- def get_mounted_volumes(self, disk_dict = None):
- # Returns a list of mounted volumes
- return (disk_dict or self.disks).get("MountPointsFromDisks",[])
-
- def get_mounted_volume_dicts(self, disk_dict = None):
- # Returns a list of dicts of name, identifier, mount point dicts
- vol_list = []
- for v in (disk_dict or self.disks).get("MountPointsFromDisks"):
- i = self.get_disk(v,disk_dict=disk_dict)
- if not i: continue # Skip - as it didn't resolve
- mount_point = self.get_mount_point(i,disk_dict=disk_dict)
- # Check if we're either not mounted - or not mounted in /Volumes/
- if not v or not (v == "/" or v.lower().startswith("/volumes/")):
- continue
- vol = {
- "name": self.get_volume_name(i,disk_dict=disk_dict),
- "identifier": self.get_identifier(i,disk_dict=disk_dict),
- "mount_point": v,
- "disk_uuid": self.get_disk_uuid(i,disk_dict=disk_dict),
- "volume_uuid": self.get_volume_uuid(i,disk_dict=disk_dict)
- }
- if "container_for" in i: vol["container_for"] = i["container_for"]
- vol_list.append(vol)
- return sorted(vol_list,key=lambda x:x["identifier"])
-
- def get_disks_and_partitions_dict(self, disk_dict = None):
- # Returns a list of dictionaries like so:
- # { "disk0" : {
- # "container": true/false,
- # "physical_stores": [
- # "diskAsB",
- # "diskXsY"
- # ],
- # "scheme": "Guid_partition_scheme",
- # "partitions" : [
- # {
- # "identifier" : "disk0s1",
- # "name" : "EFI",
- # "mount_point" : "/Volumes/EFI",
- # "container_for": "diskCsD"
- # }
- # ] } }
- disks = {}
- for d in sorted((disk_dict or self.disks).get("AllDisksAndPartitions"),key=lambda x:x.get("DAMediaBSDName")):
- if not "DAMediaBSDName" in d: continue # Malformed
- parent = d["DAMediaBSDName"]
- disks[parent] = {"partitions":[]}
- # Save if the disk is logical - and a l)ist of its physical stores
- for x in ("container","physical_stores"):
- if x in d: disks[parent][x] = d[x]
- disks[parent]["scheme"] = self.get_readable_partition_scheme(d,disk_dict=disk_dict)
- # Check if this disk is also a volume - i.e. also a leaf, and insert it in the partitions list
- partitions = d.get("Partitions",[])
- if d.get("DAMediaLeaf"):
- partitions.insert(0,d)
- for p in d.get("Partitions",[]):
- part = {
- "name": self.get_volume_name(p,disk_dict=disk_dict),
- "identifier": self.get_identifier(p,disk_dict=disk_dict),
- "mount_point": self.get_mount_point(p,disk_dict=disk_dict),
- "disk_uuid": self.get_disk_uuid(p,disk_dict=disk_dict),
- "volume_uuid": self.get_volume_uuid(p,disk_dict=disk_dict)
- }
- if "container_for" in p: part["container_for"] = p["container_for"]
- disks[parent]["partitions"].append(part)
- disks[parent]["partitions"].sort(key=lambda x:x["identifier"])
- return disks
-
- def _get_value(self, disk = None, value = None, disk_dict = None):
- if not disk or not value: return # Missing info
- if isinstance(disk,dict): return disk.get(value)
- try: return self.get_disk(disk,disk_dict=disk_dict).get(value)
- except: return
-
- def _is_uuid(self, value):
- # Helper to return whether a passed value is a UUID
- # 7C3CFDDF-920A-4924-AED6-7CD4AF6E4512
- if not isinstance(value,str): return False # Wrong type
- value = value.lower()
- # Check that all chars are hex or the separator
- if not all((x in "-0123456789abcdef" for x in value)): return False
- len_list = (8,4,4,4,12)
- chunks = value.split("-")
- # Make sure we have the right number of chunks - and
- # each chunk is the right length.
- if not len(chunks)==len(len_list): return False
- for i,chunk in enumerate(chunks):
- if not len(chunk)==len_list[i]: return False
- # Passed all the checks
- return True
-
- def get_partition_scheme(self, disk, allow_logical = True, disk_dict = None):
- # let's resolve the disk to its physical parents
- comm = self.get_parent_disk if allow_logical else self.get_physical_parent_disks
- p = comm(disk,disk_dict=disk_dict)
- if p:
- if isinstance(p,(list,tuple)): p = p[0] # Extract the first parent if need be
- if p.get("apfs"): return "APFS_container_scheme"
- elif p.get("core_storage"): return "Core_Storage_container_scheme"
- content = self.get_content(p,disk_dict=disk_dict)
- if content.lower().endswith("scheme"):
- return content
-
- def get_readable_partition_scheme(self, disk, allow_logical = True, disk_dict = None):
- s = self.get_partition_scheme(disk,disk_dict=disk_dict)
- if not s: return
- # We want to convert GUID_partition_scheme to GUID
- # We also want to translate FDisk to MBR
- joined = " ".join(["MBR" if x.lower() == "fdisk" else x.capitalize() if x!=x.upper() else x for x in s.replace("_"," ").split() if x])
- return joined
-
- def get_content(self, disk, disk_dict = None):
- return self._get_value(disk,"DAMediaContent",disk_dict=disk_dict)
-
- def get_volume_name(self, disk, disk_dict = None):
- return self._get_value(disk,"DAVolumeName",disk_dict=disk_dict)
-
- def get_volume_uuid(self, disk, disk_dict = None):
- return self._get_value(disk,"DAVolumeUUID",disk_dict=disk_dict)
-
- def get_disk_uuid(self, disk, disk_dict = None):
- return self._get_value(disk,"DAMediaUUID",disk_dict=disk_dict)
-
- def get_mount_point(self, disk, disk_dict = None):
- return self._get_value(disk,"DAVolumePath",disk_dict=disk_dict)
-
- def open_mount_point(self, disk, new_window = False, disk_dict = None):
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- mount = self.get_mount_point(disk)
- if not mount: return
- return self.r.run({"args":["open", mount]})[2] == 0
-
- def compare_version(self, v1, v2):
- # Splits the version numbers by periods and compare each value
- # Allows 0.0.10 > 0.0.9 where normal string comparison would return false
- # Also strips out any non-numeric values from each segment to avoid conflicts
- #
- # Returns True if v1 > v2, None if v1 == v2, and False if v1 < v2
- if not all((isinstance(x,str) for x in (v1,v2))):
- # Wrong types
- return False
- v1_seg = v1.split(".")
- v2_seg = v2.split(".")
- # Pad with 0s to ensure common length
- v1_seg += ["0"]*(len(v2_seg)-len(v1_seg))
- v2_seg += ["0"]*(len(v1_seg)-len(v2_seg))
- # Compare each segment - stripping non-numbers as needed
- for i in range(len(v1_seg)):
- a,b = v1_seg[i],v2_seg[i]
- try: a = int("".join([x for x in a if x.isdigit()]))
- except: a = 0
- try: b = int("".join([x for x in b if x.isdigit()]))
- except: b = 0
- if a > b: return True
- if a < b: return False
- # If we're here, both versions are the same
- return None
-
- def needs_sudo(self, disk = None, disk_dict = None):
- # Default to EFI if we didn't pass a disk
- if not disk: return self.compare_version(self.full_os_version,self.sudo_mount_version) in (True,None)
- return self.compare_version(self.full_os_version,self.sudo_mount_version) in (True,None) and self.get_content(disk,disk_dict=disk_dict).upper() in self.efi_guids
-
- def mount_partition(self, disk, disk_dict = None):
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- sudo = self.needs_sudo(disk,disk_dict=disk_dict)
- out = self.r.run({"args":["diskutil","mount",disk],"sudo":sudo})
- self.update()
- return out
-
- def unmount_partition(self, disk, disk_dict = None):
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- out = self.r.run({"args":["diskutil","unmount",disk]})
- self.update()
- return out
-
- def is_mounted(self, disk, disk_dict = None):
- disk = self.get_identifier(disk,disk_dict=disk_dict)
- if not disk: return
- m = self.get_mount_point(disk,disk_dict=disk_dict)
- return (m != None and len(m))
-
- def get_volumes(self, disk_dict = None):
- # Returns a list object with all volumes from disks
- return sorted((disk_dict or self.disks).get("VolumesFromDisks",[]))
-
-if __name__ == '__main__':
- d = Disk()
- # Gather the args
- errors = []
- args = []
- for x in sys.argv[1:]:
- if x == "/":
- args.append(x)
- continue
- if x.endswith("/"):
- x = x[:-1]
- if not x.lower().startswith("/volumes/") or len(x.split("/")) > 3:
- errors.append("'{}' is not a volume.".format(x))
- continue
- if not os.path.exists(x):
- # Doesn't exist, skip it
- errors.append("'{}' does not exist.".format(x))
- continue
- args.append(x)
- mount_list = []
- needs_sudo = d.needs_sudo()
- for x in args:
- name = d.get_volume_name(x)
- if not name: name = "Untitled"
- name = name.replace('"','\\"') # Escape double quotes in names
- efi = d.get_efi(x)
- if efi: mount_list.append((efi,name,d.is_mounted(efi),"diskutil mount {}".format(efi)))
- else: errors.append("'{}' has no ESP.".format(name))
- if mount_list:
- # We have something to mount
- efis = [x[-1] for x in mount_list if not x[2]] # Only mount those that aren't mounted
- names = [x[1] for x in mount_list if not x[2]]
- if efis: # We have something to mount here
- command = "do shell script \"{}\" with prompt \"MountEFI would like to mount the ESP{} on {}\"{}".format(
- "; ".join(efis),
- "s" if len(names) > 1 else "",
- ", ".join(names),
- " with administrator privileges" if needs_sudo else "")
- o,e,r = d.r.run({"args":["osascript","-e",command]})
- if r > 0 and len(e.strip()) and e.strip().lower().endswith("(-128)"): exit() # User canceled, bail
- # Update the disks
- d.update()
- # Walk the mounts and find out which aren't mounted
- for efi,name,mounted,comm in mount_list:
- mounted_at = d.get_mount_point(efi)
- if mounted_at: d.open_mount_point(mounted_at)
- else: errors.append("ESP for '{}' failed to mount.".format(name))
- else:
- errors.append("No disks with ESPs selected.")
- if errors:
- # Display our errors before we leave
- d.r.run({"args":["osascript","-e","display dialog \"{}\" buttons {{\"OK\"}} default button \"OK\" with icon caution".format("\n".join(errors))]})
\ No newline at end of file
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump
deleted file mode 100755
index b81958f..0000000
Binary files a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/diskdump and /dev/null differ
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py
deleted file mode 100755
index e47ddd4..0000000
--- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/plist.py
+++ /dev/null
@@ -1,612 +0,0 @@
-### ###
-# Imports #
-### ###
-
-import datetime, os, plistlib, struct, sys, itertools
-from io import BytesIO
-
-if sys.version_info < (3,0):
- # Force use of StringIO instead of cStringIO as the latter
- # has issues with Unicode strings
- from StringIO import StringIO
-
-try:
- basestring # Python 2
- unicode
-except NameError:
- basestring = str # Python 3
- unicode = str
-
-try:
- FMT_XML = plistlib.FMT_XML
- FMT_BINARY = plistlib.FMT_BINARY
-except AttributeError:
- FMT_XML = "FMT_XML"
- FMT_BINARY = "FMT_BINARY"
-
-### ###
-# Helper Methods #
-### ###
-
-def wrap_data(value):
- if not _check_py3(): return plistlib.Data(value)
- return value
-
-def extract_data(value):
- if not _check_py3() and isinstance(value,plistlib.Data): return value.data
- return value
-
-def _check_py3():
- return sys.version_info >= (3, 0)
-
-def _is_binary(fp):
- if isinstance(fp, basestring):
- return fp.startswith(b"bplist00")
- header = fp.read(32)
- fp.seek(0)
- return header[:8] == b'bplist00'
-
-### ###
-# Deprecated Functions - Remapped #
-### ###
-
-def readPlist(pathOrFile):
- if not isinstance(pathOrFile, basestring):
- return load(pathOrFile)
- with open(pathOrFile, "rb") as f:
- return load(f)
-
-def writePlist(value, pathOrFile):
- if not isinstance(pathOrFile, basestring):
- return dump(value, pathOrFile, fmt=FMT_XML, sort_keys=True, skipkeys=False)
- with open(pathOrFile, "wb") as f:
- return dump(value, f, fmt=FMT_XML, sort_keys=True, skipkeys=False)
-
-### ###
-# Remapped Functions #
-### ###
-
-def load(fp, fmt=None, use_builtin_types=None, dict_type=dict):
- if _check_py3():
- use_builtin_types = True if use_builtin_types == None else use_builtin_types
- # We need to monkey patch this to allow for hex integers - code taken/modified from
- # https://github.com/python/cpython/blob/3.8/Lib/plistlib.py
- if fmt is None:
- header = fp.read(32)
- fp.seek(0)
- for info in plistlib._FORMATS.values():
- if info['detect'](header):
- P = info['parser']
- break
- else:
- raise plistlib.InvalidFileException()
- else:
- P = plistlib._FORMATS[fmt]['parser']
- try:
- p = P(use_builtin_types=use_builtin_types, dict_type=dict_type)
- except:
- # Python 3.9 removed use_builtin_types
- p = P(dict_type=dict_type)
- if isinstance(p,plistlib._PlistParser):
- # Monkey patch!
- def end_integer():
- d = p.get_data()
- value = int(d,16) if d.lower().startswith("0x") else int(d)
- if -1 << 63 <= value < 1 << 63:
- p.add_object(value)
- else:
- raise OverflowError("Integer overflow at line {}".format(p.parser.CurrentLineNumber))
- def end_data():
- try:
- p.add_object(plistlib._decode_base64(p.get_data()))
- except Exception as e:
- raise Exception("Data error at line {}: {}".format(p.parser.CurrentLineNumber,e))
- p.end_integer = end_integer
- p.end_data = end_data
- return p.parse(fp)
- elif not _is_binary(fp):
- # Is not binary - assume a string - and try to load
- # We avoid using readPlistFromString() as that uses
- # cStringIO and fails when Unicode strings are detected
- # Don't subclass - keep the parser local
- from xml.parsers.expat import ParserCreate
- # Create a new PlistParser object - then we need to set up
- # the values and parse.
- p = plistlib.PlistParser()
- parser = ParserCreate()
- parser.StartElementHandler = p.handleBeginElement
- parser.EndElementHandler = p.handleEndElement
- parser.CharacterDataHandler = p.handleData
- # We also need to monkey patch this to allow for other dict_types, hex int support
- # proper line output for data errors, and for unicode string decoding
- def begin_dict(attrs):
- d = dict_type()
- p.addObject(d)
- p.stack.append(d)
- def end_integer():
- d = p.getData()
- value = int(d,16) if d.lower().startswith("0x") else int(d)
- if -1 << 63 <= value < 1 << 63:
- p.addObject(value)
- else:
- raise OverflowError("Integer overflow at line {}".format(parser.CurrentLineNumber))
- def end_data():
- try:
- p.addObject(plistlib.Data.fromBase64(p.getData()))
- except Exception as e:
- raise Exception("Data error at line {}: {}".format(parser.CurrentLineNumber,e))
- def end_string():
- d = p.getData()
- if isinstance(d,unicode):
- d = d.encode("utf-8")
- p.addObject(d)
- p.begin_dict = begin_dict
- p.end_integer = end_integer
- p.end_data = end_data
- p.end_string = end_string
- if isinstance(fp, unicode):
- # Encode unicode -> string; use utf-8 for safety
- fp = fp.encode("utf-8")
- if isinstance(fp, basestring):
- # It's a string - let's wrap it up
- fp = StringIO(fp)
- # Parse it
- parser.ParseFile(fp)
- return p.root
- else:
- use_builtin_types = False if use_builtin_types == None else use_builtin_types
- try:
- p = _BinaryPlistParser(use_builtin_types=use_builtin_types, dict_type=dict_type)
- except:
- # Python 3.9 removed use_builtin_types
- p = _BinaryPlistParser(dict_type=dict_type)
- return p.parse(fp)
-
-def loads(value, fmt=None, use_builtin_types=None, dict_type=dict):
- if _check_py3() and isinstance(value, basestring):
- # If it's a string - encode it
- value = value.encode()
- try:
- return load(BytesIO(value),fmt=fmt,use_builtin_types=use_builtin_types,dict_type=dict_type)
- except:
- # Python 3.9 removed use_builtin_types
- return load(BytesIO(value),fmt=fmt,dict_type=dict_type)
-def dump(value, fp, fmt=FMT_XML, sort_keys=True, skipkeys=False):
- if _check_py3():
- plistlib.dump(value, fp, fmt=fmt, sort_keys=sort_keys, skipkeys=skipkeys)
- else:
- if fmt == FMT_XML:
- # We need to monkey patch a bunch here too in order to avoid auto-sorting
- # of keys
- writer = plistlib.PlistWriter(fp)
- def writeDict(d):
- if d:
- writer.beginElement("dict")
- items = sorted(d.items()) if sort_keys else d.items()
- for key, value in items:
- if not isinstance(key, basestring):
- if skipkeys:
- continue
- raise TypeError("keys must be strings")
- writer.simpleElement("key", key)
- writer.writeValue(value)
- writer.endElement("dict")
- else:
- writer.simpleElement("dict")
- writer.writeDict = writeDict
- writer.writeln("")
- writer.writeValue(value)
- writer.writeln("")
- elif fmt == FMT_BINARY:
- # Assume binary at this point
- writer = _BinaryPlistWriter(fp, sort_keys=sort_keys, skipkeys=skipkeys)
- writer.write(value)
- else:
- # Not a proper format
- raise ValueError("Unsupported format: {}".format(fmt))
-
-def dumps(value, fmt=FMT_XML, skipkeys=False, sort_keys=True):
- if _check_py3():
- return plistlib.dumps(value, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys).decode("utf-8")
- else:
- # We avoid using writePlistToString() as that uses
- # cStringIO and fails when Unicode strings are detected
- f = StringIO()
- dump(value, f, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys)
- return f.getvalue()
-
-### ###
-# Binary Plist Stuff For Py2 #
-### ###
-
-# From the python 3 plistlib.py source: https://github.com/python/cpython/blob/3.7/Lib/plistlib.py
-# Tweaked to function on Python 2
-
-class InvalidFileException (ValueError):
- def __init__(self, message="Invalid file"):
- ValueError.__init__(self, message)
-
-_BINARY_FORMAT = {1: 'B', 2: 'H', 4: 'L', 8: 'Q'}
-
-_undefined = object()
-
-class _BinaryPlistParser:
- """
- Read or write a binary plist file, following the description of the binary
- format. Raise InvalidFileException in case of error, otherwise return the
- root object.
- see also: http://opensource.apple.com/source/CF/CF-744.18/CFBinaryPList.c
- """
- def __init__(self, use_builtin_types, dict_type):
- self._use_builtin_types = use_builtin_types
- self._dict_type = dict_type
-
- def parse(self, fp):
- try:
- # The basic file format:
- # HEADER
- # object...
- # refid->offset...
- # TRAILER
- self._fp = fp
- self._fp.seek(-32, os.SEEK_END)
- trailer = self._fp.read(32)
- if len(trailer) != 32:
- raise InvalidFileException()
- (
- offset_size, self._ref_size, num_objects, top_object,
- offset_table_offset
- ) = struct.unpack('>6xBBQQQ', trailer)
- self._fp.seek(offset_table_offset)
- self._object_offsets = self._read_ints(num_objects, offset_size)
- self._objects = [_undefined] * num_objects
- return self._read_object(top_object)
-
- except (OSError, IndexError, struct.error, OverflowError,
- UnicodeDecodeError):
- raise InvalidFileException()
-
- def _get_size(self, tokenL):
- """ return the size of the next object."""
- if tokenL == 0xF:
- m = ord(self._fp.read(1)[0]) & 0x3
- s = 1 << m
- f = '>' + _BINARY_FORMAT[s]
- return struct.unpack(f, self._fp.read(s))[0]
-
- return tokenL
-
- def _read_ints(self, n, size):
- data = self._fp.read(size * n)
- if size in _BINARY_FORMAT:
- return struct.unpack('>' + _BINARY_FORMAT[size] * n, data)
- else:
- if not size or len(data) != size * n:
- raise InvalidFileException()
- return tuple(int.from_bytes(data[i: i + size], 'big')
- for i in range(0, size * n, size))
-
- def _read_refs(self, n):
- return self._read_ints(n, self._ref_size)
-
- def _read_object(self, ref):
- """
- read the object by reference.
- May recursively read sub-objects (content of an array/dict/set)
- """
- result = self._objects[ref]
- if result is not _undefined:
- return result
-
- offset = self._object_offsets[ref]
- self._fp.seek(offset)
- token = ord(self._fp.read(1)[0])
- tokenH, tokenL = token & 0xF0, token & 0x0F
-
- if token == 0: # \x00 or 0x00
- result = None
-
- elif token == 8: # \x08 or 0x08
- result = False
-
- elif token == 9: # \x09 or 0x09
- result = True
-
- # The referenced source code also mentions URL (0x0c, 0x0d) and
- # UUID (0x0e), but neither can be generated using the Cocoa libraries.
-
- elif token == 15: # \x0f or 0x0f
- result = b''
-
- elif tokenH == 0x10: # int
- result = 0
- for k in range((2 << tokenL) - 1):
- result = (result << 8) + ord(self._fp.read(1))
- # result = int.from_bytes(self._fp.read(1 << tokenL),
- # 'big', signed=tokenL >= 3)
-
- elif token == 0x22: # real
- result = struct.unpack('>f', self._fp.read(4))[0]
-
- elif token == 0x23: # real
- result = struct.unpack('>d', self._fp.read(8))[0]
-
- elif token == 0x33: # date
- f = struct.unpack('>d', self._fp.read(8))[0]
- # timestamp 0 of binary plists corresponds to 1/1/2001
- # (year of Mac OS X 10.0), instead of 1/1/1970.
- result = (datetime.datetime(2001, 1, 1) +
- datetime.timedelta(seconds=f))
-
- elif tokenH == 0x40: # data
- s = self._get_size(tokenL)
- if self._use_builtin_types:
- result = self._fp.read(s)
- else:
- result = plistlib.Data(self._fp.read(s))
-
- elif tokenH == 0x50: # ascii string
- s = self._get_size(tokenL)
- result = self._fp.read(s).decode('ascii')
- result = result
-
- elif tokenH == 0x60: # unicode string
- s = self._get_size(tokenL)
- result = self._fp.read(s * 2).decode('utf-16be')
-
- # tokenH == 0x80 is documented as 'UID' and appears to be used for
- # keyed-archiving, not in plists.
-
- elif tokenH == 0xA0: # array
- s = self._get_size(tokenL)
- obj_refs = self._read_refs(s)
- result = []
- self._objects[ref] = result
- result.extend(self._read_object(x) for x in obj_refs)
-
- # tokenH == 0xB0 is documented as 'ordset', but is not actually
- # implemented in the Apple reference code.
-
- # tokenH == 0xC0 is documented as 'set', but sets cannot be used in
- # plists.
-
- elif tokenH == 0xD0: # dict
- s = self._get_size(tokenL)
- key_refs = self._read_refs(s)
- obj_refs = self._read_refs(s)
- result = self._dict_type()
- self._objects[ref] = result
- for k, o in zip(key_refs, obj_refs):
- key = self._read_object(k)
- if isinstance(key, plistlib.Data):
- key = key.data
- result[key] = self._read_object(o)
-
- else:
- raise InvalidFileException()
-
- self._objects[ref] = result
- return result
-
-def _count_to_size(count):
- if count < 1 << 8:
- return 1
-
- elif count < 1 << 16:
- return 2
-
- elif count << 1 << 32:
- return 4
-
- else:
- return 8
-
-_scalars = (str, int, float, datetime.datetime, bytes)
-
-class _BinaryPlistWriter (object):
- def __init__(self, fp, sort_keys, skipkeys):
- self._fp = fp
- self._sort_keys = sort_keys
- self._skipkeys = skipkeys
-
- def write(self, value):
-
- # Flattened object list:
- self._objlist = []
-
- # Mappings from object->objectid
- # First dict has (type(object), object) as the key,
- # second dict is used when object is not hashable and
- # has id(object) as the key.
- self._objtable = {}
- self._objidtable = {}
-
- # Create list of all objects in the plist
- self._flatten(value)
-
- # Size of object references in serialized containers
- # depends on the number of objects in the plist.
- num_objects = len(self._objlist)
- self._object_offsets = [0]*num_objects
- self._ref_size = _count_to_size(num_objects)
-
- self._ref_format = _BINARY_FORMAT[self._ref_size]
-
- # Write file header
- self._fp.write(b'bplist00')
-
- # Write object list
- for obj in self._objlist:
- self._write_object(obj)
-
- # Write refnum->object offset table
- top_object = self._getrefnum(value)
- offset_table_offset = self._fp.tell()
- offset_size = _count_to_size(offset_table_offset)
- offset_format = '>' + _BINARY_FORMAT[offset_size] * num_objects
- self._fp.write(struct.pack(offset_format, *self._object_offsets))
-
- # Write trailer
- sort_version = 0
- trailer = (
- sort_version, offset_size, self._ref_size, num_objects,
- top_object, offset_table_offset
- )
- self._fp.write(struct.pack('>5xBBBQQQ', *trailer))
-
- def _flatten(self, value):
- # First check if the object is in the object table, not used for
- # containers to ensure that two subcontainers with the same contents
- # will be serialized as distinct values.
- if isinstance(value, _scalars):
- if (type(value), value) in self._objtable:
- return
-
- elif isinstance(value, plistlib.Data):
- if (type(value.data), value.data) in self._objtable:
- return
-
- elif id(value) in self._objidtable:
- return
-
- # Add to objectreference map
- refnum = len(self._objlist)
- self._objlist.append(value)
- if isinstance(value, _scalars):
- self._objtable[(type(value), value)] = refnum
- elif isinstance(value, plistlib.Data):
- self._objtable[(type(value.data), value.data)] = refnum
- else:
- self._objidtable[id(value)] = refnum
-
- # And finally recurse into containers
- if isinstance(value, dict):
- keys = []
- values = []
- items = value.items()
- if self._sort_keys:
- items = sorted(items)
-
- for k, v in items:
- if not isinstance(k, basestring):
- if self._skipkeys:
- continue
- raise TypeError("keys must be strings")
- keys.append(k)
- values.append(v)
-
- for o in itertools.chain(keys, values):
- self._flatten(o)
-
- elif isinstance(value, (list, tuple)):
- for o in value:
- self._flatten(o)
-
- def _getrefnum(self, value):
- if isinstance(value, _scalars):
- return self._objtable[(type(value), value)]
- elif isinstance(value, plistlib.Data):
- return self._objtable[(type(value.data), value.data)]
- else:
- return self._objidtable[id(value)]
-
- def _write_size(self, token, size):
- if size < 15:
- self._fp.write(struct.pack('>B', token | size))
-
- elif size < 1 << 8:
- self._fp.write(struct.pack('>BBB', token | 0xF, 0x10, size))
-
- elif size < 1 << 16:
- self._fp.write(struct.pack('>BBH', token | 0xF, 0x11, size))
-
- elif size < 1 << 32:
- self._fp.write(struct.pack('>BBL', token | 0xF, 0x12, size))
-
- else:
- self._fp.write(struct.pack('>BBQ', token | 0xF, 0x13, size))
-
- def _write_object(self, value):
- ref = self._getrefnum(value)
- self._object_offsets[ref] = self._fp.tell()
- if value is None:
- self._fp.write(b'\x00')
-
- elif value is False:
- self._fp.write(b'\x08')
-
- elif value is True:
- self._fp.write(b'\x09')
-
- elif isinstance(value, int):
- if value < 0:
- try:
- self._fp.write(struct.pack('>Bq', 0x13, value))
- except struct.error:
- raise OverflowError(value) # from None
- elif value < 1 << 8:
- self._fp.write(struct.pack('>BB', 0x10, value))
- elif value < 1 << 16:
- self._fp.write(struct.pack('>BH', 0x11, value))
- elif value < 1 << 32:
- self._fp.write(struct.pack('>BL', 0x12, value))
- elif value < 1 << 63:
- self._fp.write(struct.pack('>BQ', 0x13, value))
- elif value < 1 << 64:
- self._fp.write(b'\x14' + value.to_bytes(16, 'big', signed=True))
- else:
- raise OverflowError(value)
-
- elif isinstance(value, float):
- self._fp.write(struct.pack('>Bd', 0x23, value))
-
- elif isinstance(value, datetime.datetime):
- f = (value - datetime.datetime(2001, 1, 1)).total_seconds()
- self._fp.write(struct.pack('>Bd', 0x33, f))
-
- elif isinstance(value, plistlib.Data):
- self._write_size(0x40, len(value.data))
- self._fp.write(value.data)
-
- elif isinstance(value, basestring):
- try:
- t = value.encode('ascii')
- self._write_size(0x50, len(value))
- except UnicodeEncodeError:
- t = value.encode('utf-16be')
- self._write_size(0x60, len(t) // 2)
- self._fp.write(t)
-
- elif isinstance(value, (bytes, bytearray)):
- self._write_size(0x40, len(value))
- self._fp.write(value)
-
- elif isinstance(value, (list, tuple)):
- refs = [self._getrefnum(o) for o in value]
- s = len(refs)
- self._write_size(0xA0, s)
- self._fp.write(struct.pack('>' + self._ref_format * s, *refs))
-
- elif isinstance(value, dict):
- keyRefs, valRefs = [], []
-
- if self._sort_keys:
- rootItems = sorted(value.items())
- else:
- rootItems = value.items()
-
- for k, v in rootItems:
- if not isinstance(k, basestring):
- if self._skipkeys:
- continue
- raise TypeError("keys must be strings")
- keyRefs.append(self._getrefnum(k))
- valRefs.append(self._getrefnum(v))
-
- s = len(keyRefs)
- self._write_size(0xD0, s)
- self._fp.write(struct.pack('>' + self._ref_format * s, *keyRefs))
- self._fp.write(struct.pack('>' + self._ref_format * s, *valRefs))
-
- else:
- raise TypeError(value)
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py b/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py
deleted file mode 100755
index b586adc..0000000
--- a/Utils/mountefi/Mount EFI.workflow/Contents/Scripts/run.py
+++ /dev/null
@@ -1,151 +0,0 @@
-import sys, subprocess, time, threading, shlex
-try:
- from Queue import Queue, Empty
-except:
- from queue import Queue, Empty
-
-ON_POSIX = 'posix' in sys.builtin_module_names
-
-class Run:
-
- def __init__(self):
- return
-
- def _read_output(self, pipe, q):
- try:
- for line in iter(lambda: pipe.read(1), b''):
- q.put(line)
- except ValueError:
- pass
- pipe.close()
-
- def _create_thread(self, output):
- # Creates a new queue and thread object to watch based on the output pipe sent
- q = Queue()
- t = threading.Thread(target=self._read_output, args=(output, q))
- t.daemon = True
- return (q,t)
-
- def _stream_output(self, comm, shell = False):
- output = error = ""
- p = None
- try:
- if shell and type(comm) is list:
- comm = " ".join(shlex.quote(x) for x in comm)
- if not shell and type(comm) is str:
- comm = shlex.split(comm)
- p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, universal_newlines=True, close_fds=ON_POSIX)
- # Setup the stdout thread/queue
- q,t = self._create_thread(p.stdout)
- qe,te = self._create_thread(p.stderr)
- # Start both threads
- t.start()
- te.start()
-
- while True:
- c = z = ""
- try: c = q.get_nowait()
- except Empty: pass
- else:
- sys.stdout.write(c)
- output += c
- sys.stdout.flush()
- try: z = qe.get_nowait()
- except Empty: pass
- else:
- sys.stderr.write(z)
- error += z
- sys.stderr.flush()
- if not c==z=="": continue # Keep going until empty
- # No output - see if still running
- p.poll()
- if p.returncode != None:
- # Subprocess ended
- break
- # No output, but subprocess still running - stall for 20ms
- time.sleep(0.02)
-
- o, e = p.communicate()
- return (output+o, error+e, p.returncode)
- except:
- if p:
- try: o, e = p.communicate()
- except: o = e = ""
- return (output+o, error+e, p.returncode)
- return ("", "Command not found!", 1)
-
- def _decode(self, value, encoding="utf-8", errors="ignore"):
- # Helper method to only decode if bytes type
- if sys.version_info >= (3,0) and isinstance(value, bytes):
- return value.decode(encoding,errors)
- return value
-
- def _run_command(self, comm, shell = False):
- c = None
- try:
- if shell and type(comm) is list:
- comm = " ".join(shlex.quote(x) for x in comm)
- if not shell and type(comm) is str:
- comm = shlex.split(comm)
- p = subprocess.Popen(comm, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- c = p.communicate()
- except:
- if c == None:
- return ("", "Command not found!", 1)
- return (self._decode(c[0]), self._decode(c[1]), p.returncode)
-
- def run(self, command_list, leave_on_fail = False):
- # Command list should be an array of dicts
- if type(command_list) is dict:
- # We only have one command
- command_list = [command_list]
- output_list = []
- for comm in command_list:
- args = comm.get("args", [])
- shell = comm.get("shell", False)
- stream = comm.get("stream", False)
- sudo = comm.get("sudo", False)
- stdout = comm.get("stdout", False)
- stderr = comm.get("stderr", False)
- mess = comm.get("message", None)
- show = comm.get("show", False)
-
- if not mess == None:
- print(mess)
-
- if not len(args):
- # nothing to process
- continue
- if sudo:
- # Check if we have sudo
- out = self._run_command(["which", "sudo"])
- if "sudo" in out[0]:
- # Can sudo
- if type(args) is list:
- args.insert(0, out[0].replace("\n", "")) # add to start of list
- elif type(args) is str:
- args = out[0].replace("\n", "") + " " + args # add to start of string
-
- if show:
- print(" ".join(args))
-
- if stream:
- # Stream it!
- out = self._stream_output(args, shell)
- else:
- # Just run and gather output
- out = self._run_command(args, shell)
- if stdout and len(out[0]):
- print(out[0])
- if stderr and len(out[1]):
- print(out[1])
- # Append output
- output_list.append(out)
- # Check for errors
- if leave_on_fail and out[2] != 0:
- # Got an error - leave
- break
- if len(output_list) == 1:
- # We only ran one command - just return that output
- return output_list[0]
- return output_list
diff --git a/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow b/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow
deleted file mode 100644
index 6a5b8a5..0000000
--- a/Utils/mountefi/Mount EFI.workflow/Contents/document.wflow
+++ /dev/null
@@ -1,146 +0,0 @@
-
-
-
-
- AMApplicationBuild
- 512
- AMApplicationVersion
- 2.10
- AMDocumentVersion
- 2
- actions
-
-
- action
-
- AMAccepts
-
- Container
- List
- Optional
-
- Types
-
- com.apple.applescript.object
-
-
- AMActionVersion
- 1.0.2
- AMApplication
-
- Automator
-
- AMParameterProperties
-
- source
-
-
- AMProvides
-
- Container
- List
- Types
-
- com.apple.applescript.object
-
-
- ActionBundlePath
- /System/Library/Automator/Run AppleScript.action
- ActionName
- Run AppleScript
- ActionParameters
-
- source
- on run {input, parameters}
# Hacky nonsense to export paths that aren't normally available
set export to "export PATH=/usr/local/bin:/usr/local/sbin/:$PATH; "
# Try to get the system python versions - starting with py 3
set python to ""
repeat with py in {"python3", "python"}
try
set pypath to do shell script export & "which " & py
if pypath is "/usr/bin/python3" then
# Check if we're running 10.15 or newer - and verify "xcode-select -p"
# runs properly before allowing the stub
if (do shell script "sw_vers -productVersion") ≥ "10.15" then
do shell script "xcode-select -p"
end if
end if
do shell script export & "/usr/bin/env " & py & " -V"
set python to py
exit repeat
on error errorMsg
# Didn't resolve - onto the next
end try
end repeat
if python is "" then
my print_error("Could not locate python3 or python via /usr/bin/env!", "Please download and install the latest from python.org")
return
end if
# If we got here - we have a python version to run.
# Organize the input paths
set passed_paths to ""
repeat with the_path in input
set the_text to quoted form of POSIX path of (the_path as text) as string
set passed_paths to passed_paths & " " & the_text
end repeat
# Let's make sure we have disk.py file
set target to "disk.py"
# Get the contents of the ~/Library/Services folder, and look for disk.py to run
set services to POSIX path of (path to home folder) & "Library/Services/"
set quick_action_list to do shell script "ls -1 " & quoted form of services
set quick_actions to paragraphs of quick_action_list
repeat with qa in quick_actions
set test_path to services & qa & "/Contents/Scripts/" & target
if my check_exists(test_path) is "0" then
# We got a valid path - let's run it
do shell script export & "/usr/bin/env " & python & " " & quoted form of test_path & passed_paths
return
end if
end repeat
# If we got here - then we didn't find the quick action
my print_error("Required files were not found!", "Please reinstall the latest Mount EFI quick action from https://github.com/corpnewt/MountEFI")
return
end run
on check_exists(path)
# Quick one-liner to abuse bash and see if a file/folder exists
return do shell script "if [[ -e " & quoted form of path & " ]]; then echo 0; else echo 1; fi"
end check_exists
on print_error(header, footer)
beep
display alert header & "
" & footer
end print_error
-
- BundleIdentifier
- com.apple.Automator.RunScript
- CFBundleVersion
- 1.0.2
- CanShowSelectedItemsWhenRun
-
- CanShowWhenRun
-
- Category
-
- AMCategoryUtilities
-
- Class Name
- RunScriptAction
- InputUUID
- 34AED1F9-B31F-4927-A2F3-43392E378CAC
- Keywords
-
- Run
-
- OutputUUID
- EAB751F1-47E9-4256-9F92-ED4CD9CF95F5
- UUID
- FDE567E1-0DA9-43F5-B7DC-9D30FD0B8553
- UnlocalizedApplications
-
- Automator
-
- arguments
-
- 0
-
- default value
- on run {input, parameters}
-
- (* Your script goes here *)
-
- return input
-end run
- name
- source
- required
- 0
- type
- 0
- uuid
- 0
-
-
- isViewVisible
- 1
- location
- 301.500000:558.000000
- nibPath
- /System/Library/Automator/Run AppleScript.action/Contents/Resources/Base.lproj/main.nib
-
- isViewVisible
- 1
-
-
- connectors
-
- workflowMetaData
-
- applicationBundleIDsByPath
-
- applicationPaths
-
- inputTypeIdentifier
- com.apple.Automator.fileSystemObject.folder
- outputTypeIdentifier
- com.apple.Automator.nothing
- presentationMode
- 15
- processesInput
- 0
- serviceInputTypeIdentifier
- com.apple.Automator.fileSystemObject.folder
- serviceOutputTypeIdentifier
- com.apple.Automator.nothing
- serviceProcessesInput
- 0
- systemImageName
- NSTouchBarTransferDownload
- useAutomaticInputType
- 0
- workflowTypeIdentifier
- com.apple.Automator.servicesMenu
-
-
-
diff --git a/Utils/ocvalidate/README.md b/Utils/ocvalidate/README.md
deleted file mode 100644
index 0aaf5c6..0000000
--- a/Utils/ocvalidate/README.md
+++ /dev/null
@@ -1,140 +0,0 @@
-ocvalidate
-====================
-
-Utility to validate whether a `config.plist` matches requirements and conventions imposed by OpenCore.
-
-## Usage
-- Pass one single path to `config.plist` to verify it.
-- Pass `--version` for current supported OpenCore version.
-
-## Technical background
-### At a glance
-- ocvalidate firstly calls `OcSerializeLib` which performs fundamental checks in terms of syntax and semantics. After that, the following will be checked.
-- The error message `` complained by `OcSerializeLib` indicates unknown keys that can be deprecated in new versions of OpenCore. Such keys should be ***removed*** in order to avoid undefined behaviours.
-- Under active development, newer versions of OpenCore hardly have backward compatibility at this moment. As a result, please first run `ocvalidate --version` to check which version of OpenCore is supported, and thus please only use the specific version.
-
-### Global Rules
-- All entries must be set once only. Duplication is strictly prohibited.
-- All strings (fields with plist `String` format) throughout the whole config only accept ASCII printable characters at most. Stricter rules may apply. For instance, some fields only accept specified values, as indicated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf).
-- All the paths relative to OpenCore root must be less than or equal to 128 bytes (`OC_STORAGE_SAFE_PATH_MAX`) in total including '\0' terminator.
-- Most binary patches must have `Find`, `Replace`, `Mask` (if used), and `ReplaceMask` (if used) identical size set. Also, `Find` requires `Mask` (or `Replace` requires `ReplaceMask`) to be active (set to non-zero) for corresponding bits.
-- `MinKernel` and `MaxKernel` entries should follow conventions specified in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf). (TODO: Bring decent checks for this)
-- `MinKernel` cannot be a value that is below macOS 10.4 (Darwin version 8).
-- Entries taking file system path only accept `0-9, A-Z, a-z, '_', '-', '.', '/', and '\'`.
-- Device Paths (e.g. `PciRoot(0x0)/Pci(0x1b,0x0)`) only accept strings in canonic string format.
-- Paths of UEFI Drivers only accept `0-9, A-Z, a-z, '_', '-', '.', and '/'`.
-- Entries requiring bitwise operations (e.g. `ConsoleAttributes`, `PickerAttributes`, or `ScanPolicy`) only allow known bits stated in [Configuration.pdf](https://github.com/acidanthera/OpenCorePkg/blob/master/Docs/Configuration.pdf) to be set.
-- Entries involving GUID (mainly in Section `NVRAM`) must have correct format set.
-
-### ACPI
-#### Add
-- Entry[N]->Path: Only `.aml` and `.bin` filename suffix are accepted.
-
-### Booter
-#### MmioWhitelist
-- Entry[N]->Enabled: When at least one entry is enabled, `DevirtualiseMmio` in `Booter->Quirks` should be enabled.
-#### Patch
-- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
-- Entry[N]->Identifier: Only `Any`, `Apple`, or a specified bootloader with `.efi` sufffix, are accepted.
-#### Quirks
-- When `AllowRelocationBlock` is enabled, `ProvideCustomSlide` should be enabled altogether.
-- When `EnableSafeModeSlide` is enabled, `ProvideCustomSlide` should be enabled altogether.
-- If `ProvideMaxSlide` is set to a number greater than zero, `ProvideCustomSlide` should be enabled altogether.
-- `ResizeAppleGpuBars` must be set to `0` or `-1`.
-- When `DisableVariableWrite`, `EnableWriteUnprotector`, or `ProvideCustomSlide` is enabled, `OpenRuntime.efi` should be loaded in `UEFI->Drivers`.
-
-### DeviceProperties
-- Requirements here all follow Global Rules.
-
-### Kernel
-#### Add
-- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
-- Entry[N]->BundlePath: Filename should have `.kext` suffix.
-- Entry[N]->PlistPath: Filename should have `.plist` suffix.
-- Entry[N]: If `Lilu.kext` is used, `DisableLinkeditJettison` should be enabled in `Kernel->Quirks`.
-- `BrcmFirmwareRepo.kext` must not be injected by OpenCore.
-- For some known kexts, their `BundlePath`, `ExecutablePath`, and `PlistPath` must match against each other. Current list of rules can be found [here](https://github.com/acidanthera/OpenCorePkg/blob/master/Utilities/ocvalidate/KextInfo.c).
-- Plugin kext must be placed after parent kext. For example, [plugins of Lilu](https://github.com/acidanthera/Lilu/blob/master/KnownPlugins.md) must be placed after `Lilu.kext`.
-#### Delete
-- Entry[N]->Arch: Only `Any`, `i386`, or `x86_64` are accepted.
-- Entry[N]->Identifier: At least one dot (`.`) should exist, because any identifier looks like a domain sequence (`vendor.product`).
-#### Quirks
-- `CustomSMBIOSGuid` requires `PlatformInfo->UpdateSMBIOSMode` set to `Custom`.
-- `SetApfsTrimTimeout` cannot be a value that is greater than `MAX_UINT32`, or less than `-1`.
-#### Scheme
-- KernelArch: Only `Auto`, `i386`, `i386-user32`, or `x86_64` are accepted.
-- KernelCache: Only `Auto`, `Cacheless`, `Mkext`, or `Prelinked` are accepted.
-
-### Misc
-#### BlessOverride
-- Entries cannot be `\EFI\Microsoft\Boot\bootmgfw.efi` or `\System\Library\CoreServices\boot.efi` since OpenCore knows these paths.
-#### Boot
-- HibernateMode: Only `None`, `Auto`, `RTC`, or `NVRAM` are accepted.
-- PickerMode: Only `Builtin`, `External`, or `Apple` are accepted.
-- `PickerAudioAssist` requires `AudioSupport` in `UEFI->Audio` to be enabled.
-- LauncherOption: Only `Disabled`, `Full`, `Short`, or `System` are accepted.
-- `LauncherPath` cannot be empty string.
-#### Security
-- AuthRestart: If enabled, `VirtualSMC.kext` should be present in `Kernel->Add`.
-- DmgLoading: Only `Disabled`, `Signed`, or `Any` are accepted.
-- Vault: Only `Optional`, `Basic`, or `Secure` are accepted.
-- SecureBootModel: Only `Default`, `Disabled`, `j137`, `j680`, `j132`, `j174`, `j140k`, `j780`, `j213`, `j140a`, `j152f`, `j160`, `j230k`, `j214k`, `j223`, `j215`, `j185`, `j185f`, or `x86legacy` are accepted.
-#### Serial
-- RegisterAccessWidth: Only `8` or `32` are accepted.
-- BaudRate: Only `921600`, `460800`, `230400`, `115200`, `57600`, `38400`, `19200`, `9600`, `7200`, `4800`, `3600`, `2400`, `2000`, `1800`, `1200`, `600`, `300`, `150`, `134`, `110`, `75`, or `50` are accepted.
-- PciDeviceInfo: The last byte must be `0xFF`.
-- PciDeviceInfo: Excluding the last byte `0xFF`, the rest must be divisible by 4.
-- PciDeviceInfo: Maximum allowed size is 41.
-
-### NVRAM
-- Requirements here all follow Global Rules. In addition, the following keys and values are checked:
-#### gAppleBootVariableGuid (`7C436110-AB2A-4BBB-A880-FE41995C9F82`)
-- `nvda_drv` must have type `Plist Data` with the value of `0x30` or `0x31`.
-- `boot-args` must be an ASCII string (thus `Plist String`) without trailing `\0`.
-- `bootercfg` must be an ASCII string (thus `Plist String`) without trailing `\0`.
-- `csr-active-config` must have type `Plist Data` and have length of 4 bytes.
-- `StartupMute` must have type `Plist Data` and have length of 1 byte.
-- `SystemAudioVolume` must have type `Plist Data` and have length of 1 byte.
-#### gAppleVendorVariableGuid (`4D1EDE05-38C7-4A6A-9CC6-4BCCA8B38C14`)
-- `UIScale` must have type `Plist Data` with the value of `0x01` or `0x02`.
-- `FirmwareFeatures` must have type `Plist Data` and have length of 4 bytes.
-- `ExtendedFirmwareFeatures` must have type `Plist Data` and have length of 8 bytes.
-- `FirmwareFeaturesMask` must have type `Plist Data` and have length of 4 bytes.
-- `ExtendedFirmwareFeatures` must have type `Plist Data` and have length of 8 bytes.
-- `DefaultBackgroundColor` must have type `Plist Data` and have length of 4 bytes. Also, its last byte must be `0x00`.
-
-### PlatformInfo
-- UpdateSMBIOSMode: Only `TryOverwrite`, `Create`, `Overwrite`, or `Custom` are accepted.
-#### Generic
-- SystemProductName: Only real Mac models are accepted.
-- SystemMemoryStatus: Only `Auto`, `Upgradable`, or `Soldered` are accepted.
-- SystemUUID: Only empty string, `OEM` or valid UUID are accepted.
-- ProcessorType: Only known first byte can be set.
-
-### UEFI
-#### APFS
-- When `EnableJumpstart` is enabled, `ScanPolicy` in `Misc->Security` should have `OC_SCAN_ALLOW_FS_APFS` (bit 8) set, together with `OC_SCAN_FILE_SYSTEM_LOCK` (bit 0) set. Or `ScanPolicy` should be `0` (failsafe value).
-#### Audio
-- When `AudioSupport` is enabled, `AudioDevice` must be either empty or a valid path.
-- When `AudioSupport` is enabled, `AudioOutMask` must be non-zero.
-#### Quirks
-- When `RequestBootVarRouting` is enabled, `OpenRuntime.efi` should be loaded in `UEFI->Drivers`.
-- `ResizeGpuBars` must be set to an integer value between `-1` and `19`.
-#### Drivers
-- When `OpenUsbKbDxe.efi` is in use, `KeySupport` in `UEFI->Input` should never be enabled altogether.
-- When `Ps2KeyboardDxe.efi` is in use, `KeySupport` in `UEFI->Input` should always be enabled altogether.
-- `OpenUsbKbDxe.efi` and `Ps2KeyboardDxe.efi` should never co-exist.
-- When HFS+ filesystem driver or `AudioDxe.efi` is in use, `ConnectDrivers` should be enabled altogether.
-- When `OpenCanopy.efi` is in use, `PickerMode` in `Misc->Boot` should be set to `External`.
-- When `OpenVariableRuntimeDxe.efi` is in use, its `LoadEarly` option must be set to `TRUE`.
-- `OpenRuntime.efi` must be placed after `OpenVariableRuntimeDxe.efi` when both are in use.
-- `LoadEarly` for any other driver but `OpenVariableRuntimeDxe.efi` and `OpenRuntime.efi` must be set to `FALSE`.
-#### Input
-- KeySupportMode: Only `Auto`, `V1`, `V2`, or `AMI` are accepted.
-- When `PointerSupport` is enabled, the value of `PointerSupportMode` should only be `ASUS`.
-#### Output
-- `ClearScreenOnModeSwitch`, `IgnoreTextInGraphics`, `ReplaceTabWithSpace`, and `SanitiseClearScreen` only apply to `System` TextRenderer
-- `Resolution` should match `NUMBERxNUMBER` or `NUMBERxNUMBER@NUMBER` sequences (unless it is an `Empty string` or is set to `Max`).
-- `UIScale` must be set to an integer value between `-1` and `2`.
-#### ReservedMemory
-- Type: Only `Reserved`, `LoaderCode`, `LoaderData`, `BootServiceCode`, `BootServiceData`, `RuntimeCode`, `RuntimeData`, `Available`, `Persistent`, `UnusableMemory`, `ACPIReclaimMemory`, `ACPIMemoryNVS`, `MemoryMappedIO`, `MemoryMappedIOPortSpace`, or `PalCode` are accepted.
diff --git a/Utils/ocvalidate/ocvalidate b/Utils/ocvalidate/ocvalidate
deleted file mode 100755
index ff0d53f..0000000
Binary files a/Utils/ocvalidate/ocvalidate and /dev/null differ
diff --git a/Utils/ocvalidate/ocvalidate.exe b/Utils/ocvalidate/ocvalidate.exe
deleted file mode 100755
index f6127c5..0000000
Binary files a/Utils/ocvalidate/ocvalidate.exe and /dev/null differ
diff --git a/Utils/ocvalidate/ocvalidate.linux b/Utils/ocvalidate/ocvalidate.linux
deleted file mode 100755
index 6fb767c..0000000
Binary files a/Utils/ocvalidate/ocvalidate.linux and /dev/null differ