|
@@ -131,7 +131,7 @@ class UTMData: ObservableObject {
|
|
return ProcessInfo.processInfo.globallyUniqueString
|
|
return ProcessInfo.processInfo.globallyUniqueString
|
|
}
|
|
}
|
|
|
|
|
|
- func newDefaultDriveName(type: UTMDiskImageType, forConfig: UTMConfiguration) -> String {
|
|
|
|
|
|
+ func newDefaultDrivePath(type: UTMDiskImageType, forConfig: UTMConfiguration) -> String {
|
|
let nameForId = { (i: Int) in "\(type.description)-\(i).qcow2" }
|
|
let nameForId = { (i: Int) in "\(type.description)-\(i).qcow2" }
|
|
for i in 0..<1000 {
|
|
for i in 0..<1000 {
|
|
let name = nameForId(i)
|
|
let name = nameForId(i)
|
|
@@ -143,6 +143,27 @@ class UTMData: ObservableObject {
|
|
return UUID().uuidString
|
|
return UUID().uuidString
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ func newDefaultDriveName(for config: UTMConfiguration) -> String {
|
|
|
|
+ let nameForId = { (i: Int) in "drive\(i)" }
|
|
|
|
+ for i in 0..<1000 {
|
|
|
|
+ let name = nameForId(i)
|
|
|
|
+ var free: Bool = true
|
|
|
|
+ for j in 0..<config.countDrives {
|
|
|
|
+ guard let taken = config.driveName(for: j) else {
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ if taken == name {
|
|
|
|
+ free = false
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if free {
|
|
|
|
+ return name
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return UUID().uuidString
|
|
|
|
+ }
|
|
|
|
+
|
|
// MARK: - VM functions
|
|
// MARK: - VM functions
|
|
|
|
|
|
func save(vm: UTMVirtualMachine) throws {
|
|
func save(vm: UTMVirtualMachine) throws {
|
|
@@ -348,10 +369,10 @@ class UTMData: ObservableObject {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- let name = drive.lastPathComponent
|
|
|
|
|
|
+ let path = drive.lastPathComponent
|
|
let imageType: UTMDiskImageType = drive.pathExtension.lowercased() == "iso" ? .CD : .disk
|
|
let imageType: UTMDiskImageType = drive.pathExtension.lowercased() == "iso" ? .CD : .disk
|
|
let imagesPath = config.imagesPath
|
|
let imagesPath = config.imagesPath
|
|
- let dstPath = imagesPath.appendingPathComponent(name)
|
|
|
|
|
|
+ let dstPath = imagesPath.appendingPathComponent(path)
|
|
if !fileManager.fileExists(atPath: imagesPath.path) {
|
|
if !fileManager.fileExists(atPath: imagesPath.path) {
|
|
try fileManager.createDirectory(at: imagesPath, withIntermediateDirectories: false, attributes: nil)
|
|
try fileManager.createDirectory(at: imagesPath, withIntermediateDirectories: false, attributes: nil)
|
|
}
|
|
}
|
|
@@ -361,25 +382,26 @@ class UTMData: ObservableObject {
|
|
try fileManager.moveItem(at: drive, to: dstPath)
|
|
try fileManager.moveItem(at: drive, to: dstPath)
|
|
}
|
|
}
|
|
DispatchQueue.main.async {
|
|
DispatchQueue.main.async {
|
|
|
|
+ let name = self.newDefaultDriveName(for: config)
|
|
let interface: String
|
|
let interface: String
|
|
if let target = config.systemTarget {
|
|
if let target = config.systemTarget {
|
|
interface = UTMConfiguration.defaultDriveInterface(forTarget: target, type: imageType)
|
|
interface = UTMConfiguration.defaultDriveInterface(forTarget: target, type: imageType)
|
|
} else {
|
|
} else {
|
|
interface = "none"
|
|
interface = "none"
|
|
}
|
|
}
|
|
- config.newDrive(name, type: imageType, interface: interface)
|
|
|
|
|
|
+ config.newDrive(name, path: path, type: imageType, interface: interface)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func createDrive(_ drive: VMDriveImage, for config: UTMConfiguration) throws {
|
|
func createDrive(_ drive: VMDriveImage, for config: UTMConfiguration) throws {
|
|
- var name: String = ""
|
|
|
|
|
|
+ var path: String = ""
|
|
if !drive.removable {
|
|
if !drive.removable {
|
|
guard drive.size > 0 else {
|
|
guard drive.size > 0 else {
|
|
throw NSLocalizedString("Invalid drive size.", comment: "UTMData")
|
|
throw NSLocalizedString("Invalid drive size.", comment: "UTMData")
|
|
}
|
|
}
|
|
- name = newDefaultDriveName(type: drive.imageType, forConfig: config)
|
|
|
|
|
|
+ path = newDefaultDrivePath(type: drive.imageType, forConfig: config)
|
|
let imagesPath = config.imagesPath
|
|
let imagesPath = config.imagesPath
|
|
- let dstPath = imagesPath.appendingPathComponent(name)
|
|
|
|
|
|
+ let dstPath = imagesPath.appendingPathComponent(path)
|
|
if !fileManager.fileExists(atPath: imagesPath.path) {
|
|
if !fileManager.fileExists(atPath: imagesPath.path) {
|
|
try fileManager.createDirectory(at: imagesPath, withIntermediateDirectories: false, attributes: nil)
|
|
try fileManager.createDirectory(at: imagesPath, withIntermediateDirectories: false, attributes: nil)
|
|
}
|
|
}
|
|
@@ -391,20 +413,21 @@ class UTMData: ObservableObject {
|
|
}
|
|
}
|
|
|
|
|
|
DispatchQueue.main.async {
|
|
DispatchQueue.main.async {
|
|
|
|
+ let name = self.newDefaultDriveName(for: config)
|
|
let interface = drive.interface ?? "none"
|
|
let interface = drive.interface ?? "none"
|
|
if drive.removable {
|
|
if drive.removable {
|
|
- config.newRemovableDrive(drive.imageType, interface: interface)
|
|
|
|
|
|
+ config.newRemovableDrive(name, type: drive.imageType, interface: interface)
|
|
} else {
|
|
} else {
|
|
- config.newDrive(name, type: drive.imageType, interface: interface)
|
|
|
|
|
|
+ config.newDrive(name, path: path, type: drive.imageType, interface: interface)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
func removeDrive(at index: Int, for config: UTMConfiguration) throws {
|
|
func removeDrive(at index: Int, for config: UTMConfiguration) throws {
|
|
- if let name = config.driveImagePath(for: index) {
|
|
|
|
- let path = config.imagesPath.appendingPathComponent(name);
|
|
|
|
- if fileManager.fileExists(atPath: path.path) {
|
|
|
|
- try fileManager.removeItem(at: path)
|
|
|
|
|
|
+ if let path = config.driveImagePath(for: index) {
|
|
|
|
+ let fullPath = config.imagesPath.appendingPathComponent(path);
|
|
|
|
+ if fileManager.fileExists(atPath: fullPath.path) {
|
|
|
|
+ try fileManager.removeItem(at: fullPath)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|