680845cb1c
Linux build / Determine Swift version (push) Waiting to run
Linux build / Linux compile check (push) Blocked by required conditions
Build containerization / Verify commit signatures (push) Has been skipped
Build containerization / containerization (push) Successful in 0s
201 lines
6.9 KiB
Swift
201 lines
6.9 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
// 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
|
|
|
|
/// Represents the configuration settings for an `ArchiveWriter`.
|
|
///
|
|
/// This struct allows specifying the archive format, compression filter,
|
|
/// various format-specific options, and preferred locales for string encoding.
|
|
public struct ArchiveWriterConfiguration {
|
|
public static let defaultLocales = ["en_US.UTF-8", "C.UTF-8"]
|
|
|
|
/// The desired archive format
|
|
public var format: Format
|
|
/// The compression filter to apply to the archive
|
|
public var filter: Filter
|
|
/// An array of format-specific options to apply to the archive.
|
|
/// This includes options like compression level and extended attribute format.
|
|
public var options: [Options]
|
|
/// An array of preferred locale identifiers for string encoding
|
|
public var locales: [String]
|
|
|
|
/// Initializes a new `ArchiveWriterConfiguration`.
|
|
///
|
|
/// Sets up the configuration with the specified format, filter, options, and locales.
|
|
public init(
|
|
format: Format, filter: Filter, options: [Options] = [], locales: [String] = Self.defaultLocales
|
|
) {
|
|
self.format = format
|
|
self.filter = filter
|
|
self.options = options
|
|
self.locales = locales
|
|
}
|
|
}
|
|
|
|
extension ArchiveWriter {
|
|
internal func setFormat(_ format: Format) throws {
|
|
guard let underlying = self.underlying else { throw ArchiveError.noUnderlyingArchive }
|
|
let r = archive_write_set_format(underlying, format.code)
|
|
guard r == ARCHIVE_OK else { throw ArchiveError.unableToSetFormat(r, format) }
|
|
}
|
|
|
|
internal func addFilter(_ filter: Filter) throws {
|
|
guard let underlying = self.underlying else { throw ArchiveError.noUnderlyingArchive }
|
|
let r = archive_write_add_filter(underlying, filter.code)
|
|
guard r == ARCHIVE_OK else { throw ArchiveError.unableToAddFilter(r, filter) }
|
|
}
|
|
|
|
internal func setOptions(_ options: [Options]) throws {
|
|
guard let underlying = self.underlying else { throw ArchiveError.noUnderlyingArchive }
|
|
try options.forEach {
|
|
switch $0 {
|
|
case .compressionLevel(let level):
|
|
try wrap(
|
|
archive_write_set_option(underlying, nil, "compression-level", "\(level)"),
|
|
ArchiveError.unableToSetOption, underlying: self.underlying)
|
|
case .compression(.store):
|
|
try wrap(
|
|
archive_write_set_option(underlying, nil, "compression", "store"), ArchiveError.unableToSetOption,
|
|
underlying: self.underlying)
|
|
case .compression(.deflate):
|
|
try wrap(
|
|
archive_write_set_option(underlying, nil, "compression", "deflate"), ArchiveError.unableToSetOption,
|
|
underlying: self.underlying)
|
|
case .xattrformat(let value):
|
|
let v = value.description
|
|
try wrap(
|
|
archive_write_set_option(underlying, nil, "xattrheader", v), ArchiveError.unableToSetOption,
|
|
underlying: self.underlying)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum Options {
|
|
case compressionLevel(UInt32)
|
|
case compression(Compression)
|
|
case xattrformat(XattrFormat)
|
|
|
|
public enum Compression {
|
|
case store
|
|
case deflate
|
|
}
|
|
|
|
public enum XattrFormat: String, CustomStringConvertible {
|
|
case schily
|
|
case libarchive
|
|
case all
|
|
|
|
public var description: String {
|
|
switch self {
|
|
case .libarchive:
|
|
return "LIBARCHIVE"
|
|
case .schily:
|
|
return "SCHILY"
|
|
case .all:
|
|
return "ALL"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An enumeration of the supported archive formats.
|
|
public enum Format: String, Sendable {
|
|
/// POSIX-standard `ustar` archives
|
|
case ustar
|
|
case gnutar
|
|
/// POSIX `pax interchange format` archives
|
|
case pax
|
|
case paxRestricted
|
|
/// POSIX octet-oriented cpio archives
|
|
case cpio
|
|
case cpioNewc
|
|
/// Zip archive
|
|
case zip
|
|
/// two different variants of shar archives
|
|
case shar
|
|
case sharDump
|
|
/// ISO9660 CD images
|
|
case iso9660
|
|
/// 7-Zip archives
|
|
case sevenZip
|
|
/// ar archives
|
|
case arBSD
|
|
case arGNU
|
|
/// mtree file tree descriptions
|
|
case mtree
|
|
/// XAR archives
|
|
case xar
|
|
|
|
internal var code: CInt {
|
|
switch self {
|
|
case .ustar: return ARCHIVE_FORMAT_TAR_USTAR
|
|
case .pax: return ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE
|
|
case .paxRestricted: return ARCHIVE_FORMAT_TAR_PAX_RESTRICTED
|
|
case .gnutar: return ARCHIVE_FORMAT_TAR_GNUTAR
|
|
case .cpio: return ARCHIVE_FORMAT_CPIO_POSIX
|
|
case .cpioNewc: return ARCHIVE_FORMAT_CPIO_AFIO_LARGE
|
|
case .zip: return ARCHIVE_FORMAT_ZIP
|
|
case .shar: return ARCHIVE_FORMAT_SHAR_BASE
|
|
case .sharDump: return ARCHIVE_FORMAT_SHAR_DUMP
|
|
case .iso9660: return ARCHIVE_FORMAT_ISO9660
|
|
case .sevenZip: return ARCHIVE_FORMAT_7ZIP
|
|
case .arBSD: return ARCHIVE_FORMAT_AR_BSD
|
|
case .arGNU: return ARCHIVE_FORMAT_AR_GNU
|
|
case .mtree: return ARCHIVE_FORMAT_MTREE
|
|
case .xar: return ARCHIVE_FORMAT_XAR
|
|
}
|
|
}
|
|
}
|
|
|
|
/// An enumeration of the supported filters (compression / encoding standards) for an archive.
|
|
public enum Filter: String, Sendable {
|
|
case none
|
|
case gzip
|
|
case bzip2
|
|
case compress
|
|
case lzma
|
|
case xz
|
|
case uu
|
|
case rpm
|
|
case lzip
|
|
case lrzip
|
|
case lzop
|
|
case grzip
|
|
case lz4
|
|
case zstd
|
|
|
|
internal var code: CInt {
|
|
switch self {
|
|
case .none: return ARCHIVE_FILTER_NONE
|
|
case .gzip: return ARCHIVE_FILTER_GZIP
|
|
case .bzip2: return ARCHIVE_FILTER_BZIP2
|
|
case .compress: return ARCHIVE_FILTER_COMPRESS
|
|
case .lzma: return ARCHIVE_FILTER_LZMA
|
|
case .xz: return ARCHIVE_FILTER_XZ
|
|
case .uu: return ARCHIVE_FILTER_UU
|
|
case .rpm: return ARCHIVE_FILTER_RPM
|
|
case .lzip: return ARCHIVE_FILTER_LZIP
|
|
case .lrzip: return ARCHIVE_FILTER_LRZIP
|
|
case .lzop: return ARCHIVE_FILTER_LZOP
|
|
case .grzip: return ARCHIVE_FILTER_GRZIP
|
|
case .lz4: return ARCHIVE_FILTER_LZ4
|
|
case .zstd: return ARCHIVE_FILTER_ZSTD
|
|
}
|
|
}
|
|
}
|