diff --git a/Sources/NextcloudKit/NKCommon.swift b/Sources/NextcloudKit/NKCommon.swift index 28323a1a..8e5f67a7 100644 --- a/Sources/NextcloudKit/NKCommon.swift +++ b/Sources/NextcloudKit/NKCommon.swift @@ -95,7 +95,9 @@ public struct NKCommon: Sendable { counterChunk: @escaping (_ counter: Int) -> Void = { _ in }, completion: @escaping (_ filesChunk: [(fileName: String, size: Int64)]) -> Void = { _ in }) { // Check if filesChunk is empty - if !filesChunk.isEmpty { return completion(filesChunk) } + if !filesChunk.isEmpty { + return completion(filesChunk) + } defer { NotificationCenter.default.removeObserver(self, name: notificationCenterChunkedFileStop, object: nil) @@ -113,14 +115,19 @@ public struct NKCommon: Sendable { let bufferSize = 1000000 var stop: Bool = false - NotificationCenter.default.addObserver(forName: notificationCenterChunkedFileStop, object: nil, queue: nil) { _ in stop = true } + NotificationCenter.default.addObserver(forName: notificationCenterChunkedFileStop, object: nil, queue: nil) { _ in + stop = true + } // If max chunk count is > 10000 (max count), add + 100 MB to the chunk size to reduce the count. This is an edge case. - var num: Int = Int(getFileSize(filePath: inputDirectory + "/" + fileName) / Int64(chunkSize)) + let inputFilePath = inputDirectory + "/" + fileName + let totalSize = getFileSize(filePath: inputFilePath) + var num: Int = Int(totalSize / Int64(chunkSize)) + if num > 10000 { - chunkSize = chunkSize + 100000000 + chunkSize += 100_000_000 + num = Int(totalSize / Int64(chunkSize)) // ricalcolo } - num = Int(getFileSize(filePath: inputDirectory + "/" + fileName) / Int64(chunkSize)) numChunks(num) if !fileManager.fileExists(atPath: outputDirectory, isDirectory: &isDirectory) { @@ -132,7 +139,7 @@ public struct NKCommon: Sendable { } do { - reader = try .init(forReadingFrom: URL(fileURLWithPath: inputDirectory + "/" + fileName)) + reader = try .init(forReadingFrom: URL(fileURLWithPath: inputFilePath)) } catch { return completion([]) } @@ -152,7 +159,7 @@ public struct NKCommon: Sendable { } let chunkRemaining: Int = chunkSize - chunk - let buffer = reader?.readData(ofLength: min(bufferSize, chunkRemaining)) + let rawBuffer = reader?.readData(ofLength: min(bufferSize, chunkRemaining)) if writer == nil { let fileNameChunk = String(counter) @@ -167,10 +174,11 @@ public struct NKCommon: Sendable { filesChunk.append((fileName: fileNameChunk, size: 0)) } - if let buffer = buffer { - writer?.write(buffer) - chunk = chunk + buffer.count - return buffer.count + if let rawBuffer = rawBuffer { + let safeBuffer = Data(rawBuffer) // secure copy + writer?.write(safeBuffer) + chunk = chunk + safeBuffer.count + return safeBuffer.count } filesChunk = [] return 0 diff --git a/Sources/NextcloudKit/NextcloudKit+Upload.swift b/Sources/NextcloudKit/NextcloudKit+Upload.swift index 15241b57..14d0cabc 100644 --- a/Sources/NextcloudKit/NextcloudKit+Upload.swift +++ b/Sources/NextcloudKit/NextcloudKit+Upload.swift @@ -244,17 +244,29 @@ public extension NextcloudKit { let freeDisk = ((fsAttributes[FileAttributeKey.systemFreeSize] ?? 0) as? Int64) ?? 0 #elseif os(visionOS) || os(iOS) var freeDisk: Int64 = 0 - let fileURL = URL(fileURLWithPath: directory as String) + let outputPath = fileChunksOutputDirectory ?? directory + let outputURL = URL(fileURLWithPath: outputPath) + do { - let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey]) - if let capacity = values.volumeAvailableCapacityForImportantUsage { - freeDisk = capacity + let keys: Set = [ + .volumeAvailableCapacityForImportantUsageKey, + .volumeAvailableCapacityKey + ] + let values = try outputURL.resourceValues(forKeys: keys) + + if let importantUsage = values.volumeAvailableCapacityForImportantUsage { + freeDisk = importantUsage + } else if let legacyCapacity = values.volumeAvailableCapacity { + freeDisk = Int64(legacyCapacity) } - } catch { } + } catch { + // fallback zero + freeDisk = 0 + } #endif #if os(visionOS) || os(iOS) - if freeDisk < fileNameLocalSize * 4 { + if freeDisk < fileNameLocalSize * 2 { // It seems there is not enough space to send the file return completion(account, nil, nil, .errorChunkNoEnoughMemory) }