From aa70cd39585fa23edd94288b84f8b2360b6e2e0f Mon Sep 17 00:00:00 2001 From: osy <50960678+osy@users.noreply.github.com> Date: Wed, 3 Aug 2022 12:47:14 -0700 Subject: [PATCH] vm(qemu): support virtfs/9p file sharing Resolves #2184 --- .../UTMQemuConfiguration+Arguments.swift | 19 +++++++++++++++++++ Managers/UTMQemuVirtualMachine+SPICE.h | 1 - Managers/UTMQemuVirtualMachine+SPICE.m | 14 ++++++-------- Managers/UTMQemuVirtualMachine.m | 2 ++ Managers/UTMVirtualMachineExtension.swift | 12 ++++++++++++ Platform/Shared/VMRemovableDrivesView.swift | 2 +- .../VMDisplayQemuDisplayController.swift | 2 +- 7 files changed, 41 insertions(+), 11 deletions(-) diff --git a/Configuration/UTMQemuConfiguration+Arguments.swift b/Configuration/UTMQemuConfiguration+Arguments.swift index e4061028e..6bbce5de1 100644 --- a/Configuration/UTMQemuConfiguration+Arguments.swift +++ b/Configuration/UTMQemuConfiguration+Arguments.swift @@ -682,6 +682,25 @@ extension UTMQemuConfiguration { f("virtserialport,chardev=charchannel1,id=channel1,name=org.spice-space.webdav.0") f("-chardev") f("spiceport,name=org.spice-space.webdav.0,id=charchannel1") + } else if sharing.directoryShareMode == .virtfs, let url = sharing.directoryShareUrl { + f("-fsdev") + "local" + "id=virtfs0" + "path=" + url + "security_model=mapped-xattr" + if sharing.isDirectoryShareReadOnly { + "readonly=on" + } + f() + f("-device") + if system.architecture == .s390x { + "virtio-9p-ccw" + } else { + "virtio-9p-pci" + } + "fsdev=virtfs0" + "mount_tag=share" } } } diff --git a/Managers/UTMQemuVirtualMachine+SPICE.h b/Managers/UTMQemuVirtualMachine+SPICE.h index 752c7c2a6..9ca22c7cb 100644 --- a/Managers/UTMQemuVirtualMachine+SPICE.h +++ b/Managers/UTMQemuVirtualMachine+SPICE.h @@ -20,7 +20,6 @@ NS_ASSUME_NONNULL_BEGIN @interface UTMQemuVirtualMachine (SPICE) -@property (nonatomic, readonly) BOOL hasShareDirectoryEnabled; @property (nonatomic, readonly) BOOL hasUsbRedirection; - (BOOL)changeSharedDirectory:(NSURL *)url error:(NSError * _Nullable *)error; diff --git a/Managers/UTMQemuVirtualMachine+SPICE.m b/Managers/UTMQemuVirtualMachine+SPICE.m index e31b43062..c5c535d00 100644 --- a/Managers/UTMQemuVirtualMachine+SPICE.m +++ b/Managers/UTMQemuVirtualMachine+SPICE.m @@ -56,10 +56,6 @@ - (UTMSpiceIO *)spiceIoWithError:(NSError * _Nullable __autoreleasing *)error { #pragma mark - Shared Directory -- (BOOL)hasShareDirectoryEnabled { - return self.config.qemuHasWebdavSharing; -} - - (BOOL)saveSharedDirectory:(NSURL *)url error:(NSError * _Nullable __autoreleasing *)error { [url startAccessingSecurityScopedResource]; NSData *bookmark = [url bookmarkDataWithOptions:kUTMBookmarkCreationOptions @@ -82,11 +78,13 @@ - (BOOL)changeSharedDirectory:(NSURL *)url error:(NSError * _Nullable __autorele // if we haven't started the VM yet, save the URL for when the VM starts return [self saveSharedDirectory:url error:error]; } - UTMSpiceIO *spiceIO = [self spiceIoWithError:error]; - if (!spiceIO) { - return NO; + if (self.config.qemuHasWebdavSharing) { + UTMSpiceIO *spiceIO = [self spiceIoWithError:error]; + if (!spiceIO) { + return NO; + } + [spiceIO changeSharedDirectory:url]; } - [spiceIO changeSharedDirectory:url]; return [self saveSharedDirectory:url error:error]; } diff --git a/Managers/UTMQemuVirtualMachine.m b/Managers/UTMQemuVirtualMachine.m index 33e24e835..5d1b6eec6 100644 --- a/Managers/UTMQemuVirtualMachine.m +++ b/Managers/UTMQemuVirtualMachine.m @@ -136,6 +136,8 @@ - (void)_vmStartWithCompletion:(void (^)(NSError * _Nullable))completion { [self.logging logToFile:self.config.qemuDebugLogURL]; } + [self prepareConfigurationForStart]; + if (self.isRunningAsSnapshot) { self.config.qemuIsDisposable = self.isRunningAsSnapshot; } else { diff --git a/Managers/UTMVirtualMachineExtension.swift b/Managers/UTMVirtualMachineExtension.swift index f08a8e254..7634ae71d 100644 --- a/Managers/UTMVirtualMachineExtension.swift +++ b/Managers/UTMVirtualMachineExtension.swift @@ -193,6 +193,18 @@ public extension UTMQemuVirtualMachine { } } } + + /// Sets up values in VM configuration corrosponding to per-device data like sharing path + @objc func prepareConfigurationForStart() { + if config.qemuConfig!.sharing.directoryShareMode != .none { + var stale: Bool = false + if let bookmark = viewState.sharedDirectory, let url = try? URL(resolvingBookmarkData: bookmark, options: kUTMBookmarkResolutionOptions, bookmarkDataIsStale: &stale) { + config.qemuConfig!.sharing.directoryShareUrl = url + } else { + logger.error("Cannot resolve bookmark for share path '\(viewState.sharedDirectoryPath ?? "nil")'") + } + } + } } extension UTMDrive: Identifiable { diff --git a/Platform/Shared/VMRemovableDrivesView.swift b/Platform/Shared/VMRemovableDrivesView.swift index 456809463..883c74719 100644 --- a/Platform/Shared/VMRemovableDrivesView.swift +++ b/Platform/Shared/VMRemovableDrivesView.swift @@ -54,7 +54,7 @@ struct VMRemovableDrivesView: View { Group { - if vm.hasShareDirectoryEnabled { + if vm.config.qemuConfig!.sharing.directoryShareMode != .none { HStack { title Spacer() diff --git a/Platform/macOS/Display/VMDisplayQemuDisplayController.swift b/Platform/macOS/Display/VMDisplayQemuDisplayController.swift index 562d88644..df1c8bdfb 100644 --- a/Platform/macOS/Display/VMDisplayQemuDisplayController.swift +++ b/Platform/macOS/Display/VMDisplayQemuDisplayController.swift @@ -62,7 +62,7 @@ class VMDisplayQemuWindowController: VMDisplayWindowController { } #endif drivesToolbarItem.isEnabled = vmQemuConfig.drives.count > 0 - sharedFolderToolbarItem.isEnabled = qemuVM.hasShareDirectoryEnabled + sharedFolderToolbarItem.isEnabled = vmQemuConfig.sharing.directoryShareMode == .webdav // virtfs cannot dynamically change usbToolbarItem.isEnabled = qemuVM.hasUsbRedirection window!.title = defaultTitle window!.subtitle = defaultSubtitle