From 95a9eb1c587cbd19d88e75f1e8fef4ef71c02c2d Mon Sep 17 00:00:00 2001 From: kt programs Date: Fri, 20 Jan 2023 17:07:59 +0800 Subject: [PATCH] data: support sparse copy across volumes Use copyfile(3) with COPYFILE_DATA_SPARSE flag which attempts to preserve sparseness when copying across different volumes, which FileManger.copyItem(at:, to:) doesn't. Cloning behaviour from FileManger.copyItem(at:, to:) is preserved with the COPYFILE_CLONE flag. --- Platform/UTMData.swift | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Platform/UTMData.swift b/Platform/UTMData.swift index 84003e3a8..e070f9c60 100644 --- a/Platform/UTMData.swift +++ b/Platform/UTMData.swift @@ -464,7 +464,7 @@ class UTMData: ObservableObject { let newName: String = newDefaultVMName(base: vm.detailsTitleLabel) let newPath = UTMVirtualMachine.virtualMachinePath(newName, inParentURL: documentsURL) - try fileManager.copyItem(at: vm.path, to: newPath) + try copyItemWithCopyfile(at: vm.path, to: newPath) guard let newVM = UTMVirtualMachine(url: newPath) else { throw NSLocalizedString("Failed to clone VM.", comment: "UTMData") } @@ -487,7 +487,7 @@ class UTMData: ObservableObject { if fileManager.fileExists(atPath: url.path) { try fileManager.removeItem(at: url) } - try fileManager.copyItem(at: sourceUrl, to: url) + try copyItemWithCopyfile(at: sourceUrl, to: url) } /// Save a copy of the VM and all data to arbitary location and delete the original data @@ -635,6 +635,15 @@ class UTMData: ObservableObject { await listAdd(vm: vm) await listSelect(vm: vm) } + + func copyItemWithCopyfile(at srcURL: URL, to dstURL: URL) throws { +// let state = copyfile_state_alloc() + let status = copyfile(srcURL.path, dstURL.path, nil, copyfile_flags_t(COPYFILE_ALL | COPYFILE_RECURSIVE | COPYFILE_CLONE | COPYFILE_DATA_SPARSE)) +// copyfile_state_free(state) + if status < 0 { + throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) + } + } // MARK: - Downloading VMs