CloverBootloader/CloverApp/Clover/Disks.swift
vectorsigma72 b06c4d4d41 Clover.app v1.02 Beta
Clver.app:
Corrected a bug that was causing the installer to fail on unknown drivers.

CloverDaemonNew :
Now is registered with the Power notifications (sleep and wake), so that can clean up nvram.plist files created by third partu kexts.
At shut down it now delete the following nvram keys:
efi-backup-boot-device
efi-backup-boot-device-data
install-product-url
previous-system-uuid

Clover.app promoted to Beta.
2019-11-09 18:03:22 +01:00

353 lines
12 KiB
Swift

//
// Disks.swift
// Clover
//
// Created by vector sigma on 19/10/2019.
// Copyright © 2019 CloverHackyColor. All rights reserved.
//
import Cocoa
import IOKit
import IOKit.serial
import IOKit.kext
import CoreFoundation
import DiskArbitration
import SystemConfiguration
let kNotAvailable : String = "N/A"
/// Get DADisk dictionary from DiskArbitration from the given disk name or mount point.
func getDAdiskDescription(from diskOrMtp: String) -> NSDictionary? {
var dict : NSDictionary? = nil
if let session = DASessionCreate(kCFAllocatorDefault) {
if diskOrMtp.hasPrefix("/") &&
!diskOrMtp.hasPrefix("/dev/disk") &&
FileManager.default.fileExists(atPath: diskOrMtp) {
let volume : CFURL = URL(fileURLWithPath: diskOrMtp) as CFURL
if let disk = DADiskCreateFromVolumePath(kCFAllocatorDefault, session, volume) {
dict = DADiskCopyDescription(disk)
}
} else if diskOrMtp.hasPrefix("/dev/disk") ||
diskOrMtp.hasPrefix("disk") {
var ndisk = diskOrMtp
if ndisk.hasPrefix("/dev/disk") {
ndisk = (ndisk as NSString).replacingOccurrences(of: "/dev/", with: "")
}
if let disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, ndisk) {
dict = DADiskCopyDescription(disk)
}
}
}
return dict
}
/// Check disk or mount point is writable (kDADiskDescriptionMediaWritableKey).
func isWritable(diskOrMtp: String) -> Bool {
var isWritable : Bool = false
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if let val = dict.object(forKey: kDADiskDescriptionMediaWritableKey) as? NSNumber {
isWritable = val.boolValue
}
}
return isWritable
}
/// Get the media content name (kDADiskDescriptionMediaContentKey).
func getMediaContent(from diskOrMtp: String) -> String? {
var content : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionMediaContentKey) != nil) {
content = dict.object(forKey: kDADiskDescriptionMediaContentKey) as? String
}
}
return content
}
/// get the Partition Scheme Map from the parent disk (kDADiskDescriptionMediaContentKey).
func getPartitionSchemeMap(from diskOrMtp: String) -> String? {
var sheme : String? = nil
if let dadisk = getBSDParent(of: diskOrMtp) {
if let dict : NSDictionary = getDAdiskDescription(from: dadisk) {
if (dict.object(forKey: kDADiskDescriptionMediaContentKey) != nil) {
sheme = dict.object(forKey: kDADiskDescriptionMediaContentKey) as? String
}
}
}
return sheme
}
/// Find the mountpoint for the given disk object. You can pass also a mount point to se if it is valid.
func getMountPoint(from diskOrMtp: String) -> String? {
// kDADiskDescriptionVolumePathKey
var mountPoint : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionVolumePathKey) != nil) {
let temp : AnyObject = dict.object(forKey: kDADiskDescriptionVolumePathKey) as AnyObject
if temp is NSURL {
mountPoint = (dict.object(forKey: kDADiskDescriptionVolumePathKey) as? URL)?.path
} else if temp is NSString {
mountPoint = dict.object(forKey: kDADiskDescriptionVolumePathKey) as? String
}
}
}
return mountPoint
}
/// Find the Volume name: be aware that this is not the mount point name.
func getVolumeName(from diskOrMtp: String) -> String? {
// kDADiskDescriptionVolumeNameKey
var name : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionVolumeNameKey) != nil) {
name = dict.object(forKey: kDADiskDescriptionVolumeNameKey) as? String
}
}
return name
}
/// Get partition UUID for the given volume: This is not a disk UUID.
func getVolumeUUID(from diskOrMtp: String) -> String? {
// kDADiskDescriptionVolumeUUIDKey
var uuid : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionVolumeUUIDKey) != nil) {
let cfuuid :CFUUID = dict.object(forKey: kDADiskDescriptionVolumeUUIDKey) as! CFUUID
uuid = CFUUIDCreateString(kCFAllocatorDefault, cfuuid)! as String
//print(uuid!)
}
}
return uuid
}
/// Get disk uuid for the given diskx. This is not a Volume UUID but a media UUID.
func getDiskUUID(from diskOrMtp: String) -> String? {
// kDADiskDescriptionVolumeUUIDKey
var uuid : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: getBSDParent(of: diskOrMtp)!) {
if (dict.object(forKey: kDADiskDescriptionMediaUUIDKey) != nil) {
let temp : AnyObject = dict.object(forKey: kDADiskDescriptionMediaUUIDKey) as AnyObject
if temp is NSUUID {
uuid = (dict.object(forKey: kDADiskDescriptionMediaUUIDKey) as? UUID)?.uuidString
} else if temp is NSString {
uuid = dict.object(forKey: kDADiskDescriptionMediaUUIDKey) as? String
}
}
}
return uuid
}
/// Get Media Name (kDADiskDescriptionMediaNameKey).
func getMediaName(from diskOrMtp: String) -> String? {
var name : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionMediaNameKey) != nil) {
name = (dict.object(forKey: kDADiskDescriptionMediaNameKey) as? String)!
}
}
return name
}
/// Get Media Name (kDADiskDescriptionDeviceProtocolKey).
func getDeviceProtocol(from diskOrMtp: String) -> String {
var prot : String = kNotAvailable
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionDeviceProtocolKey) != nil) {
prot = (dict.object(forKey: kDADiskDescriptionDeviceProtocolKey) as? String)!
}
}
return prot
}
/// Get all BSDName in the System.
func getAlldisks() -> NSDictionary {
let match_dictionary: CFMutableDictionary = IOServiceMatching("IOMedia")
var entry_iterator: io_iterator_t = 0
let allDisks = NSMutableDictionary()
if IOServiceGetMatchingServices(kIOMasterPortDefault, match_dictionary, &entry_iterator) == kIOReturnSuccess {
//let serviceObject: io_registry_entry_t
//var serviceObject : UnsafeMutablePointer<io_registry_entry_t>
var serviceObject : io_registry_entry_t = 0
repeat {
serviceObject = IOIteratorNext(entry_iterator)
if serviceObject != 0 {
var serviceDictionary : Unmanaged<CFMutableDictionary>?
if (IORegistryEntryCreateCFProperties(serviceObject,
&serviceDictionary,
kCFAllocatorDefault,
0) != kIOReturnSuccess) {
IOObjectRelease(serviceObject)
continue
}
let d : NSDictionary = (serviceDictionary?.takeRetainedValue())!
if (d.object(forKey: kIOBSDNameKey) != nil) {
allDisks.setValue(d, forKey: (d.object(forKey: kIOBSDNameKey) as! String))
}
}
} while serviceObject != 0
IOObjectRelease(entry_iterator)
}
return allDisks
}
/// Get FileSystem for the given disk or mount point.
func getFS(from diskOrMtp: String) -> String? {
var fs : String? = nil
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
var temp : String = ""
if (dict.object(forKey: kDADiskDescriptionVolumeKindKey) != nil) {
temp = dict.object(forKey: kDADiskDescriptionVolumeKindKey) as! String
// if msdos we would know if is fat32, exfat etc..
if temp.lowercased() == "msdos" {
// Since last few OSes (..on 10.13) the DAVolumeType
// contains a string like ""MS-DOS (FAT32)" so that we can identify the real fs
// w/o using statfs.
if (dict.object(forKey: kDADiskDescriptionVolumeTypeKey) != nil) {
let volType : String = dict.object(forKey: kDADiskDescriptionVolumeTypeKey) as! String
if (volType.lowercased().range(of: "exfat") != nil) {
temp = "exFAT"
} else if (volType.lowercased().range(of: "fat16") != nil) {
temp = "FAT16"
} else if (volType.lowercased().range(of: "fat32") != nil) {
temp = "FAT32"
}
}
}
fs = temp
}
}
return fs
}
/// Get all ESP (EFI System Partition) in the System.
func getAllESPs() -> [String] {
var allEsps : [String] = [String]()
for disk in getAlldisks().allKeys {
let mediaContent = getMediaContent(from: disk as! String) ?? ""
if getMediaName(from: disk as! String) == "EFI System Partition" &&
mediaContent == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B"{
if !allEsps.contains(disk as! String) {
allEsps.append(disk as! String)
}
}
}
return allEsps
}
/// Get a list of ESP that have a mount point.
func getListOfMountedEsp() -> [String] {
var mounted : [String] = [String]()
for bsdName in getAllESPs() {
if isMountPoint(path: bsdName) {
mounted.append(bsdName)
}
}
return mounted
}
/// get and array of currently mounted volumes
func getVolumes() -> [String] {
var mounted : [String] = [String]()
let all = getAlldisks().allKeys
for b in all {
let bsd : String = b as! String
if let mp = getMountPoint(from: bsd) {
mounted.append(mp)
}
}
return mounted
}
/// Find the BSDName of the given mount point.
func getBSDName(of mountpoint: String) -> String? {
if let dict : NSDictionary = getDAdiskDescription(from: mountpoint) {
if (dict.object(forKey: kDADiskDescriptionMediaBSDNameKey) != nil) {
return dict.object(forKey: kDADiskDescriptionMediaBSDNameKey) as? String
}
}
return nil
}
/// Find the BSDName of the given parent disk.
func getBSDParent(of mountpointORDevDisk: String) -> String? {
// DAMediaBSDUnit
if let dict : NSDictionary = getDAdiskDescription(from: mountpointORDevDisk) {
if (dict.object(forKey: kDADiskDescriptionMediaBSDUnitKey) != nil) {
return "disk" + ((dict.object(forKey: kDADiskDescriptionMediaBSDUnitKey) as? NSNumber)?.stringValue)!
}
}
return nil
}
/// Return the partition slice number (as string) for the given disk or mount point.
func getPartitionSlice(of mountpointORDevDisk: String) -> String? {
if let dict : NSDictionary = getDAdiskDescription(from: mountpointORDevDisk) {
if (dict.object(forKey: kDADiskDescriptionMediaBSDNameKey) != nil) {
let disk = (dict.object(forKey: kDADiskDescriptionMediaBSDNameKey) as? String)!
if (disk.range(of: "s") != nil) {
let arr : [String] = disk.components(separatedBy: "s")
if arr.count == 3 { /* dis k0s 1 */
return arr.last
}
}
}
}
return nil
}
/// Return the image (NSImage) for the given mount point or disk object.
func getIconFor(volume mountpointORDevDisk: String) -> NSImage? {
var image : NSImage? = nil
// get a customized icon.. if any
if isMountPoint(path: mountpointORDevDisk) {
let mtp : String = getMountPoint(from: mountpointORDevDisk)!
if FileManager.default.fileExists(atPath: mtp + "/.VolumeIcon.icns") {
image = NSImage(byReferencingFile: mtp + "/.VolumeIcon.icns")
return image
}
}
// .. otherwise get a System icon
if let daDict : NSDictionary = getDAdiskDescription(from: mountpointORDevDisk) {
if let iconDict = daDict.object(forKey: kDADiskDescriptionMediaIconKey) as? NSDictionary,
let iconName = iconDict.object(forKey: kIOBundleResourceFileKey ) as? String {
let identifier = iconDict.object(forKey: kCFBundleIdentifierKey as String) as! CFString
let url : CFURL = Unmanaged.takeRetainedValue(KextManagerCreateURLForBundleIdentifier(kCFAllocatorDefault, identifier))()
//print(url)
if let kb = Bundle(url: url as URL) {
image = NSImage(byReferencingFile:
kb.path(forResource: iconName.deletingFileExtension, ofType: iconName.fileExtension) ?? "")
}
}
}
return image
}
/// Boolean value indicanting if the given mount point or disk is internal.
func isInternalDevice(diskOrMtp: String) -> Bool {
if let dict : NSDictionary = getDAdiskDescription(from: diskOrMtp) {
if (dict.object(forKey: kDADiskDescriptionDeviceInternalKey) != nil) {
return ((dict.object(forKey: kDADiskDescriptionDeviceInternalKey) as? NSNumber)?.boolValue)!
}
}
return false
}
/// Boolean value indicanting if the given path is a valid mount point for a disk object.
func isMountPoint(path: String) -> Bool {
let mtp : String? = getMountPoint(from: path)
return (mtp != nil)
}