From 776bfa84944fbcd5fb24f72b8f059f89252809c5 Mon Sep 17 00:00:00 2001 From: Francesco Paolo Severino <francescopaolo.severino@gmail.com> Date: Sun, 22 Sep 2024 11:34:20 +0200 Subject: [PATCH] Try again with `swift-system` --- Package.swift | 4 +++ Sources/Zip/Zip.swift | 63 +++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 38 deletions(-) diff --git a/Package.swift b/Package.swift index 16468037..74401811 100644 --- a/Package.swift +++ b/Package.swift @@ -14,6 +14,9 @@ let package = Package( products: [ .library(name: "Zip", targets: ["Zip"]) ], + dependencies: [ + .package(url: "https://github.com/apple/swift-system", from: "1.3.2"), + ], targets: [ .target( name: "CMinizip", @@ -26,6 +29,7 @@ let package = Package( name: "Zip", dependencies: [ .target(name: "CMinizip"), + .product(name: "SystemPackage", package: "swift-system"), ], cSettings: [ .define("_CRT_SECURE_NO_WARNINGS", .when(platforms: [.windows])), diff --git a/Sources/Zip/Zip.swift b/Sources/Zip/Zip.swift index 6f3ca0df..3c64e566 100644 --- a/Sources/Zip/Zip.swift +++ b/Sources/Zip/Zip.swift @@ -11,6 +11,7 @@ import FoundationEssentials #else import Foundation #endif +import SystemPackage @_implementationOnly import CMinizip /// Main class that handles zipping and unzipping of files. @@ -69,7 +70,7 @@ public class Zip { progressTracker.kind = ProgressKind.file // Begin unzipping - let zip = unzOpen64(path) + let zip = unzOpen64(FilePath(path).string) defer { unzClose(zip) } if unzGoToFirstFile(zip) != UNZ_OK { throw ZipError.unzipFail @@ -99,11 +100,6 @@ public class Zip { var pathString = String(cString: fileName) - #if os(Windows) - // Colons are not allowed in Windows file names. - pathString = pathString.replacingOccurrences(of: ":", with: "_") - #endif - guard !pathString.isEmpty else { throw ZipError.unzipFail } @@ -121,24 +117,12 @@ public class Zip { throw ZipError.unzipFail } - let directoryAttributes: [FileAttributeKey: Any]? - #if (os(Linux) || os(Windows)) && swift(<6.0) - // On Linux and Windows, setting attributes is not yet really implemented. - directoryAttributes = nil - #else - let creationDate = Date() - directoryAttributes = [ - .creationDate: creationDate, - .modificationDate: creationDate - ] - #endif - do { if isDirectory { - try FileManager.default.createDirectory(atPath: fullPath, withIntermediateDirectories: true, attributes: directoryAttributes) + try FileManager.default.createDirectory(atPath: fullPath, withIntermediateDirectories: true) } else { let parentDirectory = (fullPath as NSString).deletingLastPathComponent - try FileManager.default.createDirectory(atPath: parentDirectory, withIntermediateDirectories: true, attributes: directoryAttributes) + try FileManager.default.createDirectory(atPath: parentDirectory, withIntermediateDirectories: true) } } catch {} if FileManager.default.fileExists(atPath: fullPath) && !isDirectory && !overwrite { @@ -146,19 +130,28 @@ public class Zip { ret = unzGoToNextFile(zip) } - var writeBytes: UInt64 = 0 - let filePointer: UnsafeMutablePointer<FILE>? = fopen(fullPath, "wb") - while let filePointer { - let readBytes = unzReadCurrentFile(zip, &buffer, bufferSize) - guard readBytes > 0 else { break } - guard fwrite(buffer, Int(readBytes), 1, filePointer) == 1 else { - throw ZipError.unzipFail + var writeBytes: Int = 0 + do { + let fd = try FileDescriptor.open( + FilePath(fullPath), + .writeOnly, + options: [.append, .create], + permissions: .ownerReadWrite + ) + try fd.closeAfter { + while true { + let readBytes = unzReadCurrentFile(zip, &buffer, bufferSize) + guard readBytes > 0 else { break } + writeBytes += try fd.writeAll(buffer[..<Int(readBytes)]) + } } - writeBytes += UInt64(readBytes) + } catch let error as Errno where error == .isDirectory { + // Skip files that are directories + } catch { + // If they are not directories, re-throw any other error + throw error } - if let filePointer { fclose(filePointer) } - if unzCloseCurrentFile(zip) == UNZ_CRCERROR { throw ZipError.unzipFail } @@ -187,15 +180,9 @@ public class Zip { } if let fileHandler = fileOutputHandler, - let encodedString = fullPath.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) { - #if os(Windows) - let fileUrlString = "file:///\(encodedString)" - #else - let fileUrlString = encodedString - #endif - if let fileUrl = URL(string: fileUrlString) { + let encodedString = fullPath.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), + let fileUrl = URL(string: FilePath(encodedString).string) { fileHandler(fileUrl) - } } progressTracker.completedUnitCount = Int64(currentPosition)