From 6b6791cea97dd4baa84e934e87e53deccda71339 Mon Sep 17 00:00:00 2001 From: Yuta Saito Date: Fri, 26 Jul 2024 07:46:36 +0000 Subject: [PATCH] Implement `_copyRegularFile` for WASI without `sendfile` WASI doesn't have `sendfile`, so we need to implement the copy in user space with `read` and `write`. It's not as efficient as `sendfile`, but it's the best we can do. --- .../FileManager/FileOperations.swift | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Sources/FoundationEssentials/FileManager/FileOperations.swift b/Sources/FoundationEssentials/FileManager/FileOperations.swift index 8e67a771f..9596cc604 100644 --- a/Sources/FoundationEssentials/FileManager/FileOperations.swift +++ b/Sources/FoundationEssentials/FileManager/FileOperations.swift @@ -871,12 +871,31 @@ enum _FileOperations { let chunkSize: Int = Int(fileInfo.st_blksize) var current: off_t = 0 + #if os(WASI) + // WASI doesn't have sendfile, so we need to do it in user space with read/write + try withUnsafeTemporaryAllocation(of: UInt8.self, capacity: chunkSize) { buffer in + while current < total { + let readSize = Swift.min(total - Int(current), chunkSize) + let bytesRead = read(srcfd, buffer.baseAddress, readSize) + guard bytesRead >= 0 else { + try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr)) + return + } + guard write(dstfd, buffer.baseAddress, bytesRead) == bytesRead else { + try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr)) + return + } + current += off_t(bytesRead) + } + } + #else while current < total { guard sendfile(dstfd, srcfd, ¤t, Swift.min(total - Int(current), chunkSize)) != -1 else { try delegate.throwIfNecessary(errno, String(cString: srcPtr), String(cString: dstPtr)) return } } + #endif } #endif