@@ -158,86 +158,14 @@ public final class Archiver: Sendable {
158158 let source = source. standardizedFileURL
159159 let destination = destination. standardizedFileURL
160160
161- // TODO: ArchiveReader needs some enhancement to support buffered uncompression
162161 let reader = try ArchiveReader (
163162 format: . paxRestricted,
164163 filter: . gzip,
165164 file: source
166165 )
167-
168- for (entry, data) in reader {
169- guard let path = entry. path else {
170- continue
171- }
172- let uncompressPath = destination. appendingPathComponent ( path)
173-
174- let fileManager = FileManager . default
175- switch entry. fileType {
176- case . blockSpecial, . characterSpecial, . socket:
177- continue
178- case . directory:
179- try fileManager. createDirectory (
180- at: uncompressPath,
181- withIntermediateDirectories: true ,
182- attributes: [
183- FileAttributeKey . posixPermissions: entry. permissions
184- ]
185- )
186- case . regular:
187- try fileManager. createDirectory (
188- at: uncompressPath. deletingLastPathComponent ( ) ,
189- withIntermediateDirectories: true ,
190- attributes: [
191- FileAttributeKey . posixPermissions: 0o755
192- ]
193- )
194- let success = fileManager. createFile (
195- atPath: uncompressPath. path,
196- contents: data,
197- attributes: [
198- FileAttributeKey . posixPermissions: entry. permissions
199- ]
200- )
201- if !success {
202- throw POSIXError . fromErrno ( )
203- }
204- try data. write ( to: uncompressPath)
205- case . symbolicLink:
206- guard let target = entry. symlinkTarget else {
207- continue
208- }
209- try fileManager. createDirectory (
210- at: uncompressPath. deletingLastPathComponent ( ) ,
211- withIntermediateDirectories: true ,
212- attributes: [
213- FileAttributeKey . posixPermissions: 0o755
214- ]
215- )
216- try fileManager. createSymbolicLink ( atPath: uncompressPath. path, withDestinationPath: target)
217- continue
218- default :
219- continue
220- }
221-
222- // FIXME: uid/gid for compress.
223- try fileManager. setAttributes (
224- [ . posixPermissions: NSNumber ( value: entry. permissions) ] ,
225- ofItemAtPath: uncompressPath. path
226- )
227-
228- if let creationDate = entry. creationDate {
229- try fileManager. setAttributes (
230- [ . creationDate: creationDate] ,
231- ofItemAtPath: uncompressPath. path
232- )
233- }
234-
235- if let modificationDate = entry. modificationDate {
236- try fileManager. setAttributes (
237- [ . modificationDate: modificationDate] ,
238- ofItemAtPath: uncompressPath. path
239- )
240- }
166+ let rejectedMembers = try reader. extractContents ( to: destination)
167+ if !rejectedMembers. isEmpty {
168+ throw Error . rejectedArchiveMembers ( rejectedMembers)
241169 }
242170 }
243171
@@ -248,18 +176,14 @@ public final class Archiver: Sendable {
248176 writerConfiguration: ArchiveWriterConfiguration ,
249177 hasher: inout SHA256
250178 ) throws {
251- let archivedPathsByHostPath = entryInfo. reduce ( into: [ String: [ URL] ] ( ) ) { result, info in
252- result [ info. pathOnHost. path, default: [ ] ] . append ( info. pathInArchive)
253- }
254-
255179 let archiver = try ArchiveWriter ( configuration: writerConfiguration)
256180 try archiver. open ( file: destination)
257181
258182 let encoder = JSONEncoder ( )
259183 encoder. outputFormatting = . sortedKeys
260184
261185 for info in entryInfo {
262- guard let entry = try Self . _createEntry ( entryInfo: info, archivedPathsByHostPath : archivedPathsByHostPath ) else {
186+ guard let entry = try Self . _createEntry ( entryInfo: info) else {
263187 throw Error . failedToCreateEntry
264188 }
265189 let hashInfo = ArchiveEntryHashInfo (
@@ -324,7 +248,6 @@ public final class Archiver: Sendable {
324248
325249 private static func _createEntry(
326250 entryInfo: ArchiveEntryInfo ,
327- archivedPathsByHostPath: [ String : [ URL ] ] = [ : ] ,
328251 pathPrefix: String = " "
329252 ) throws -> WriteEntry ? {
330253 let entry = WriteEntry ( )
@@ -341,11 +264,8 @@ public final class Archiver: Sendable {
341264 case . symbolicLink:
342265 entry. fileType = . symbolicLink
343266 entry. size = 0
344- entry. symlinkTarget = Self . _rewriteArchivedAbsoluteSymlinkTarget (
345- status. symlinkTarget ?? " " ,
346- entryInfo: entryInfo,
347- archivedPathsByHostPath: archivedPathsByHostPath
348- )
267+ // Match Docker build-context semantics and preserve the original target verbatim.
268+ entry. symlinkTarget = status. symlinkTarget
349269 }
350270
351271 #if os(macOS)
@@ -469,51 +389,6 @@ public final class Archiver: Sendable {
469389 return trimmedPath
470390 }
471391
472- private static func _rewriteArchivedAbsoluteSymlinkTarget(
473- _ symlinkTarget: String ,
474- entryInfo: ArchiveEntryInfo ,
475- archivedPathsByHostPath: [ String : [ URL ] ]
476- ) -> String {
477- guard symlinkTarget. hasPrefix ( " / " ) else {
478- return symlinkTarget
479- }
480-
481- let targetPath = URL ( fileURLWithPath: symlinkTarget)
482- . standardizedFileURL
483- . resolvingSymlinksInPath ( )
484- . path
485- guard let targetArchivePaths = archivedPathsByHostPath [ targetPath] , targetArchivePaths. count == 1 , let targetArchivePath = targetArchivePaths. first else {
486- return symlinkTarget
487- }
488-
489- let sourceDirectory = entryInfo. pathInArchive. deletingLastPathComponent ( ) . relativePath
490- return Self . _relativeArchivePath ( fromDirectory: sourceDirectory, to: targetArchivePath. relativePath)
491- }
492-
493- private static func _relativeArchivePath( fromDirectory: String , to path: String ) -> String {
494- let fromComponents = Self . _archivePathComponents ( fromDirectory)
495- let toComponents = Self . _archivePathComponents ( path)
496-
497- var commonPrefixCount = 0
498- while commonPrefixCount < fromComponents. count,
499- commonPrefixCount < toComponents. count,
500- fromComponents [ commonPrefixCount] == toComponents [ commonPrefixCount]
501- {
502- commonPrefixCount += 1
503- }
504-
505- let upwardTraversal = Array ( repeating: " .. " , count: fromComponents. count - commonPrefixCount)
506- let remainder = Array ( toComponents. dropFirst ( commonPrefixCount) )
507- let relativeComponents = upwardTraversal + remainder
508- return relativeComponents. isEmpty ? " . " : relativeComponents. joined ( separator: " / " )
509- }
510-
511- private static func _archivePathComponents( _ path: String ) -> [ String ] {
512- NSString ( string: path) . pathComponents. filter { component in
513- component != " / " && component != " . "
514- }
515- }
516-
517392 private static func _isSymbolicLink( _ path: URL ) throws -> Bool {
518393 let resourceValues = try path. resourceValues ( forKeys: [ . isSymbolicLinkKey] )
519394 if let isSymbolicLink = resourceValues. isSymbolicLink {
@@ -526,16 +401,19 @@ public final class Archiver: Sendable {
526401}
527402
528403extension Archiver {
529- public enum Error : Swift . Error , CustomStringConvertible {
404+ public enum Error : Swift . Error , CustomStringConvertible , Equatable {
530405 case failedToCreateEntry
531406 case fileDoesNotExist( _ url: URL )
407+ case rejectedArchiveMembers( [ String ] )
532408
533409 public var description : String {
534410 switch self {
535411 case . failedToCreateEntry:
536412 return " failed to create entry "
537413 case . fileDoesNotExist( let url) :
538414 return " file \( url. path) does not exist "
415+ case . rejectedArchiveMembers( let members) :
416+ return " rejected archive members: \( members. joined ( separator: " , " ) ) "
539417 }
540418 }
541419 }
0 commit comments