Skip to content
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
62b6acf
Added .runAsSnapshot to UTMAppleConfiguration.swift
PicoCreator Mar 18, 2022
96df2a6
Adding runAsSnapshot toggle on the UI
PicoCreator Mar 19, 2022
7e5783b
Experimental "runAsSnapshot" for apple VM
PicoCreator Mar 19, 2022
fe07b9e
Fixing beginers swift errors
PicoCreator Mar 19, 2022
f2b20ef
Fixing of compilation errors (swift noob here)
PicoCreator Mar 19, 2022
ff2357b
more swift compilation fixes
PicoCreator Mar 19, 2022
cc8d6e3
more swift syntax fixes
PicoCreator Mar 19, 2022
5e48986
more swift tweaks
PicoCreator Mar 19, 2022
5cfdf7d
still trying =|
PicoCreator Mar 19, 2022
e31e008
fixing the let try (i should install the xcode)
PicoCreator Mar 19, 2022
d4b9380
more attempts at fixing the apple config
PicoCreator Mar 19, 2022
d7ce877
Still figuring out swift
PicoCreator Mar 19, 2022
9935034
Added comments for copyItem
PicoCreator Mar 19, 2022
70f594e
Merge branch 'utmapp:master' into runAsSnapshot-for-macos
PicoCreator Apr 7, 2022
eb20232
Made suggested change, for triggering cleanupDriveSnapShot when VM stops
PicoCreator Apr 7, 2022
4b1507b
renamed resetDriveSnapshot with setupDriveSnapshot
PicoCreator Apr 7, 2022
ff191aa
Standardise SnapShot to Snapshot
PicoCreator Apr 7, 2022
4a18aaa
Apply suggested swift code formatting
PicoCreator Apr 7, 2022
6cc2c6e
Additional swift formatting change
PicoCreator Apr 7, 2022
f7f2f70
commenting clarification for copyItem
PicoCreator Apr 7, 2022
5e65160
Adding system wide "isRunAsSnapshot"
PicoCreator Apr 7, 2022
24813eb
Systemwide --snapshot toggle
PicoCreator Apr 7, 2022
7112e26
Fixed wrong var ref
PicoCreator Apr 7, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 62 additions & 1 deletion Configuration/UTMAppleConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,23 @@ final class UTMAppleConfiguration: UTMConfigurable, Codable, ObservableObject {
}
return urls
}

/// Remove the snapshot URL image, this can be done as part of VM cleanup
func cleanupDriveSnapShot() throws {
for i in diskImages.indices {
try diskImages[i].cleanupDriveSnapShot()
}
}

/// Perform a snapshot clone of the current image URL to the snapshot URL
/// this is required for the snapshotURL image to "work"
func resetDriveSnapShot() throws {
for i in diskImages.indices {
if( diskImages[i].runAsSnapshot ) {
Comment thread
PicoCreator marked this conversation as resolved.
Outdated
try diskImages[i].resetDriveSnapShot()
}
}
}
}

struct Bootloader: Codable {
Expand Down Expand Up @@ -864,13 +881,15 @@ struct DiskImage: Codable, Hashable, Identifiable {
var sizeMib: Int
var isReadOnly: Bool
var isExternal: Bool
var runAsSnapshot: Bool
var imageURL: URL?
private var uuid = UUID() // for identifiable

private enum CodingKeys: String, CodingKey {
case sizeMib
case isReadOnly
case isExternal
case runAsSnapshot
case imagePath
case imageBookmark
}
Expand All @@ -891,12 +910,14 @@ struct DiskImage: Codable, Hashable, Identifiable {
sizeMib = newSize
isReadOnly = false
isExternal = false
runAsSnapshot = false
}

init(importImage url: URL, isReadOnly: Bool = false, isExternal: Bool = false) {
init(importImage url: URL, isReadOnly: Bool = false, isExternal: Bool = false, runAsSnapshot: Bool = false) {
self.imageURL = url
self.isReadOnly = isReadOnly
self.isExternal = isExternal
self.runAsSnapshot = runAsSnapshot
if let attributes = try? url.resourceValues(forKeys: [.fileSizeKey]), let fileSize = attributes.fileSize {
sizeMib = fileSize / bytesInMib
} else {
Expand All @@ -912,6 +933,7 @@ struct DiskImage: Codable, Hashable, Identifiable {
sizeMib = try container.decode(Int.self, forKey: .sizeMib)
isReadOnly = try container.decode(Bool.self, forKey: .isReadOnly)
isExternal = try container.decode(Bool.self, forKey: .isExternal)
runAsSnapshot = try container.decode(Bool.self, forKey: .runAsSnapshot)
if !isExternal, let imagePath = try container.decodeIfPresent(String.self, forKey: .imagePath) {
imageURL = dataURL.appendingPathComponent(imagePath)
} else if let bookmark = try container.decodeIfPresent(Data.self, forKey: .imageBookmark) {
Expand All @@ -925,6 +947,7 @@ struct DiskImage: Codable, Hashable, Identifiable {
try container.encode(sizeMib, forKey: .sizeMib)
try container.encode(isReadOnly, forKey: .isReadOnly)
try container.encode(isExternal, forKey: .isExternal)
try container.encode(runAsSnapshot, forKey: .runAsSnapshot)
if !isExternal {
try container.encodeIfPresent(imageURL?.lastPathComponent, forKey: .imagePath)
} else {
Expand All @@ -941,7 +964,45 @@ struct DiskImage: Codable, Hashable, Identifiable {
}
}

/// Returns the snapshot equivalent URL for the current image
/// Does not actually prepare the snapshot (this is done via resetDriveSnapShot)
func snapshotURL() throws -> URL? {
var snapshotURL = imageURL
snapshotURL = snapshotURL?.appendingPathComponent(".snapshot")
return snapshotURL
Comment thread
PicoCreator marked this conversation as resolved.
Outdated
}

/// Remove the snapshot URL image, this can be done as part of VM cleanup
func cleanupDriveSnapShot() throws {
if let snapshotURL = try snapshotURL() {
// this is intentionally allowed to return false, as the file may not exists
try FileManager.default.removeItem( at: snapshotURL )
Comment thread
PicoCreator marked this conversation as resolved.
Outdated
}
}

/// Perform a snapshot clone of the current image URL to the snapshot URL
/// this is required for the snapshotURL image to "work"
func resetDriveSnapShot() throws {
// Perform any needed cleanup first
try cleanupDriveSnapShot()

// and make a copy of the provided imageURL
if let snapshotURL = try snapshotURL(), let imageURL = imageURL {
// lets setup the snapshot file
// (currently i have no idea if this optimizes when under APFS)
try FileManager.default.copyItem( at: imageURL, to: snapshotURL )
Comment thread
PicoCreator marked this conversation as resolved.
Outdated
}
}

/// Return the VZDiskImageStorageDeviceAttachment using the snapshotURL if runAsSnapshot is enabled
/// else returns using the imageURL if its configured.
func vzDiskImage() throws -> VZDiskImageStorageDeviceAttachment? {
if runAsSnapshot, let snapshotURL = try snapshotURL() {
return try VZDiskImageStorageDeviceAttachment(url: snapshotURL, readOnly: isReadOnly)
} else {
return nil
}

if let imageURL = imageURL {
return try VZDiskImageStorageDeviceAttachment(url: imageURL, readOnly: isReadOnly)
} else {
Expand Down
2 changes: 2 additions & 0 deletions Managers/UTMAppleVirtualMachine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ import Virtualization
}
fsConfig.share = self?.makeDirectoryShare(from: newShares)
}

try appleConfig.resetDriveSnapShot()
Comment thread
PicoCreator marked this conversation as resolved.
Outdated
}
apple = VZVirtualMachine(configuration: appleConfig.apple, queue: vmQueue)
apple.delegate = self
Expand Down
1 change: 1 addition & 0 deletions Platform/macOS/VMConfigAppleDriveDetailsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ struct VMConfigAppleDriveDetailsView: View {
TextField("Name", text: .constant(diskImage.imageURL?.lastPathComponent ?? NSLocalizedString("(New Drive)", comment: "VMConfigAppleDriveDetailsView")))
.disabled(true)
Toggle("Read Only?", isOn: $diskImage.isReadOnly)
Toggle("Run using a snapshot? (similar to qemu --snapshot)", isOn: $diskImage.runAsSnapshot)
Button(action: onDelete) {
Label("Delete Drive", systemImage: "externaldrive.badge.minus")
.foregroundColor(.red)
Expand Down