//===----------------------------------------------------------------------===// // Copyright © 2025-2026 Apple Inc. and the Containerization project authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //===----------------------------------------------------------------------===// import CArchive import Foundation /// An enumeration of the errors that can be thrown while interacting with an archive. public enum ArchiveError: Error, CustomStringConvertible { case unableToCreateArchive case noUnderlyingArchive case noArchiveInCallback case noDelegateConfigured case delegateFreedBeforeCallback case unableToSetFormat(CInt, Format) case unableToAddFilter(CInt, Filter) case unableToWriteEntryHeader(CInt) case unableToWriteData(CLong) case unableToCloseArchive(CInt) case unableToOpenArchive(CInt) case unableToSetOption(CInt) case failedToSetLocale(locales: [String]) case failedToGetProperty(String, URLResourceKey) case failedToDetectFilter case failedToDetectFormat case failedToExtractArchive(String) case failedToCreateArchive(String) case invalidBaseAddressArchiveWrite /// Description of the error public var description: String { switch self { case .unableToCreateArchive: return "unable to create an archive." case .noUnderlyingArchive: return "no underlying archive was provided." case .noArchiveInCallback: return "no archive was provided in the callback." case .noDelegateConfigured: return "no delegate was configured." case .delegateFreedBeforeCallback: return "the delegate was freed before the callback was invoked." case .unableToSetFormat(let code, let name): return "unable to set the archive format \(name), code \(code)" case .unableToAddFilter(let code, let name): return "unable to set the archive filter \(name), code \(code)" case .unableToWriteEntryHeader(let code): return "unable to write the entry header to the archive, code \(code)" case .unableToWriteData(let code): return "unable to write data to the archive, code \(code)" case .unableToCloseArchive(let code): return "unable to close the archive, code \(code)" case .unableToOpenArchive(let code): return "unable to open the archive, code \(code)" case .unableToSetOption(_): return "unable to set an option on the archive." case .failedToSetLocale(let locales): return "failed to set locale to \(locales)" case .failedToGetProperty(let path, let propertyName): return "failed to read property \(propertyName) from file at path \(path)" case .failedToDetectFilter: return "failed to detect filter from archive." case .failedToDetectFormat: return "failed to detect format from archive." case .failedToExtractArchive(let reason): return "failed to extract archive: \(reason)" case .failedToCreateArchive(let reason): return "failed to create archive: \(reason)" case .invalidBaseAddressArchiveWrite: return "got an invalid base address for pointer when writing data to archive" } } } public struct LibArchiveError: Error { public let source: ArchiveError public let description: String } func wrap(_ f: @autoclosure () -> CInt, _ e: (CInt) -> ArchiveError, underlying: OpaquePointer? = nil) throws { let result = f() guard result == ARCHIVE_OK else { let error = e(result) guard let underlying = underlying, let description = archive_error_string(underlying).map(String.init(cString:)) else { throw error } throw LibArchiveError(source: error, description: description) } }