Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check Symlink Containment #306

Merged
merged 6 commits into from
Dec 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2017-2023 Thomas Zoechling (https://www.peakstep.com)
Copyright (c) 2017-2024 Thomas Zoechling (https://www.peakstep.com)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+BackingConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+BackingConfiguration.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+Helpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+Helpers.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+MemoryFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+MemoryFile.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+Progress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+Progress.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
17 changes: 13 additions & 4 deletions Sources/ZIPFoundation/Archive+Reading.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+Reading.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand All @@ -18,10 +18,12 @@ extension Archive {
/// - url: The destination file URL.
/// - bufferSize: The maximum size of the read buffer and the decompression buffer (if needed).
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - allowUncontainedSymlinks: Optional flag to allow symlinks that point to paths outside the destination.
/// - progress: A progress object that can be used to track or cancel the extract operation.
/// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`.
/// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
public func extract(_ entry: Entry, to url: URL, bufferSize: Int = defaultReadChunkSize, skipCRC32: Bool = false,
public func extract(_ entry: Entry, to url: URL, bufferSize: Int = defaultReadChunkSize,
skipCRC32: Bool = false, allowUncontainedSymlinks: Bool = false,
progress: Progress? = nil) throws -> CRC32 {
guard bufferSize > 0 else {
throw ArchiveError.invalidBufferSize
Expand All @@ -30,7 +32,7 @@ extension Archive {
var checksum = CRC32(0)
switch entry.type {
case .file:
guard !fileManager.itemExists(at: url) else {
guard fileManager.itemExists(at: url) == false else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path])
}
try fileManager.createParentDirectoryStructure(for: url)
Expand All @@ -49,11 +51,18 @@ extension Archive {
checksum = try self.extract(entry, bufferSize: bufferSize, skipCRC32: skipCRC32,
progress: progress, consumer: consumer)
case .symlink:
guard !fileManager.itemExists(at: url) else {
guard fileManager.itemExists(at: url) == false else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path])
}
let consumer = { (data: Data) in
guard let linkPath = String(data: data, encoding: .utf8) else { throw ArchiveError.invalidEntryPath }

let parentURL = url.deletingLastPathComponent()
let isAbsolutePath = (linkPath as NSString).isAbsolutePath
let linkURL = URL(fileURLWithPath: linkPath, relativeTo: isAbsolutePath ? nil : parentURL)
let isContained = allowUncontainedSymlinks || linkURL.isContained(in: parentURL)
guard isContained else { throw ArchiveError.uncontainedSymlink }

try fileManager.createParentDirectoryStructure(for: url)
try fileManager.createSymbolicLink(atPath: url.path, withDestinationPath: linkPath)
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+ReadingDeprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+ReadingDeprecated.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+Writing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+Writing.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+WritingDeprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+WritingDeprecated.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Archive+ZIP64.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
4 changes: 3 additions & 1 deletion Sources/ZIPFoundation/Archive.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Archive.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down Expand Up @@ -90,6 +90,8 @@ public final class Archive: Sequence {
case invalidCentralDirectoryEntryCount
/// Thrown when an archive does not contain the required End of Central Directory Record.
case missingEndOfCentralDirectoryRecord
/// Thrown when an entry contains a symlink pointing to a path outside the destination directory.
case uncontainedSymlink
}

/// The access mode for an `Archive`.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Data+Compression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Data+Compression.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Data+CompressionDeprecated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Data+CompressionDeprecated.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Data+Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Data+Serialization.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Entry+Serialization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Entry+Serialization.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Entry+ZIP64.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Entry+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/Entry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Entry.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
13 changes: 9 additions & 4 deletions Sources/ZIPFoundation/FileManager+ZIP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// FileManager+ZIP.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down Expand Up @@ -87,10 +87,12 @@ extension FileManager {
/// - sourceURL: The file URL pointing to an existing ZIP file.
/// - destinationURL: The file URL that identifies the destination directory of the unzip operation.
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - allowUncontainedSymlinks: Optional flag to allow symlinks that point to paths outside the destination.
/// - progress: A progress object that can be used to track or cancel the unzip operation.
/// - pathEncoding: Encoding for entry paths. Overrides the encoding specified in the archive.
/// - Throws: Throws an error if the source item does not exist or the destination URL is not writable.
public func unzipItem(at sourceURL: URL, to destinationURL: URL, skipCRC32: Bool = false,
public func unzipItem(at sourceURL: URL, to destinationURL: URL,
skipCRC32: Bool = false, allowUncontainedSymlinks: Bool = false,
progress: Progress? = nil, pathEncoding: String.Encoding? = nil) throws {
let fileManager = FileManager()
guard fileManager.itemExists(at: sourceURL) else {
Expand All @@ -114,9 +116,12 @@ extension FileManager {
if let progress = progress {
let entryProgress = archive.makeProgressForReading(entry)
progress.addChild(entryProgress, withPendingUnitCount: entryProgress.totalUnitCount)
crc32 = try archive.extract(entry, to: entryURL, skipCRC32: skipCRC32, progress: entryProgress)
crc32 = try archive.extract(entry, to: entryURL,
skipCRC32: skipCRC32, allowUncontainedSymlinks: allowUncontainedSymlinks,
progress: entryProgress)
} else {
crc32 = try archive.extract(entry, to: entryURL, skipCRC32: skipCRC32)
crc32 = try archive.extract(entry, to: entryURL,
skipCRC32: skipCRC32, allowUncontainedSymlinks: allowUncontainedSymlinks)
}

func verifyChecksumIfNecessary() throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ZIPFoundation/URL+ZIP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// URL+ZIP.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationArchiveTests+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Tests/ZIPFoundationTests/ZIPFoundationArchiveTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationErrorConditionTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationDataSerializationTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationEntryTests+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
2 changes: 1 addition & 1 deletion Tests/ZIPFoundationTests/ZIPFoundationEntryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationEntryTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationErrorConditionTests+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationErrorConditionTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationFileAttributeTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationFileManagerTests+ZIP64.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
24 changes: 22 additions & 2 deletions Tests/ZIPFoundationTests/ZIPFoundationFileManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationFileManagerTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down Expand Up @@ -97,7 +97,7 @@ extension ZIPFoundationTests {
for entry in archive {
let directoryURL = destinationURL.appendingPathComponent(entry.path)
itemsExist = fileManager.itemExists(at: directoryURL)
if !itemsExist { break }
if itemsExist == false { break }
}
XCTAssert(itemsExist)
}
Expand Down Expand Up @@ -142,6 +142,26 @@ extension ZIPFoundationTests {
throws: Archive.ArchiveError.missingEndOfCentralDirectoryRecord)
}

func testUnzipUncontainedSymlink() throws {
let fileManager = FileManager()
let archive = self.archive(for: #function, mode: .read)
let destinationURL = self.createDirectory(for: #function)
XCTAssertSwiftError(try fileManager.unzipItem(at: archive.url, to: destinationURL),
throws: Archive.ArchiveError.uncontainedSymlink)

var linkArchiveURL = ZIPFoundationTests.tempZipDirectoryURL
linkArchiveURL.appendPathComponent(self.archiveName(for: #function))
let linkURL = linkArchiveURL.deletingLastPathComponent()
let linkTarget = linkURL.path
let linkArchive = try XCTUnwrap(try? Archive(url: linkArchiveURL, accessMode: .create))
try? linkArchive.addEntry(with: "link", type: .symlink, uncompressedSize: Int64(4),
provider: { (_, _) -> Data in
return linkTarget.data(using: .utf8) ?? Data()
})
try? fileManager.unzipItem(at: linkArchiveURL, to: destinationURL, allowUncontainedSymlinks: true)
XCTAssert(fileManager.itemExists(at: destinationURL.appendingPathComponent("link")))
}

// On Darwin platforms, we want the same behavior as the system-provided ZIP utilities.
// On the Mac, this includes the graphical Archive Utility as well as the `ditto`
// command line tool.
Expand Down
2 changes: 1 addition & 1 deletion Tests/ZIPFoundationTests/ZIPFoundationMemoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// ZIPFoundationMemoryTests.swift
// ZIPFoundation
//
// Copyright © 2017-2023 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Copyright © 2017-2024 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
Expand Down
Loading
Loading