@@ -96,7 +96,7 @@ public final class Archiver: Sendable {
9696 guard let entry = try Self . _createEntry ( entryInfo: info) else {
9797 throw Error . failedToCreateEntry
9898 }
99- hasher. update ( data: try encoder. encode ( info ) )
99+ hasher. update ( data: try encoder. encode ( entry ) )
100100 try Self . _compressFile ( item: info. pathOnHost, entry: entry, archiver: archiver, hasher: & hasher)
101101 }
102102 try archiver. finishEncoding ( )
@@ -110,30 +110,31 @@ public final class Archiver: Sendable {
110110
111111 // MARK: private functions
112112 private static func _compressFile( item: URL , entry: WriteEntry , archiver: ArchiveWriter , hasher: inout SHA256 ) throws {
113- guard let stream = InputStream ( url: item) else {
114- return
115- }
116-
117113 let writer = archiver. makeTransactionWriter ( )
118-
119114 let bufferSize = Int ( 1 . mib ( ) )
120115 let readBuffer = UnsafeMutablePointer< UInt8> . allocate( capacity: bufferSize)
121-
122- stream. open ( )
123116 try writer. writeHeader ( entry: entry)
124- while true {
125- let byteRead = stream. read ( readBuffer, maxLength: bufferSize)
126- if byteRead <= 0 {
127- break
128- } else {
129- let data = Data ( bytes: readBuffer, count: byteRead)
130- hasher. update ( data: data)
131- try data. withUnsafeBytes { pointer in
132- try writer. writeChunk ( data: pointer)
117+ if entry. fileType == . regular {
118+ // We need to write the data into the archive only if its a regular file
119+ // Symlinks and directories require us to only write the archive header
120+ guard let stream = InputStream ( url: item) else {
121+ throw Error . failedToCreateInputStream ( item)
122+ }
123+ stream. open ( )
124+ while true {
125+ let byteRead = stream. read ( readBuffer, maxLength: bufferSize)
126+ if byteRead <= 0 {
127+ break
128+ } else {
129+ let data = Data ( bytesNoCopy: UnsafeMutableRawPointer ( mutating: readBuffer) , count: byteRead, deallocator: . none)
130+ hasher. update ( data: data)
131+ try data. withUnsafeBytes { pointer in
132+ try writer. writeChunk ( data: pointer)
133+ }
133134 }
134135 }
136+ stream. close ( )
135137 }
136- stream. close ( )
137138 try writer. finish ( )
138139 }
139140
@@ -214,30 +215,54 @@ public final class Archiver: Sendable {
214215 let trimmedPath = String ( decodedPath. suffix ( from: pathPrefix. endIndex) )
215216 return trimmedPath
216217 }
217-
218- private static func _isSymbolicLink( _ path: URL ) throws -> Bool {
219- let resourceValues = try path. resourceValues ( forKeys: [ . isSymbolicLinkKey] )
220- if let isSymbolicLink = resourceValues. isSymbolicLink {
221- if isSymbolicLink {
222- return true
223- }
224- }
225- return false
226- }
227218}
228219
229220extension Archiver {
230221 public enum Error : Swift . Error , CustomStringConvertible {
231222 case failedToCreateEntry
232223 case fileDoesNotExist( _ url: URL )
224+ case failedToCreateInputStream( _ url: URL )
233225
234226 public var description : String {
235227 switch self {
236228 case . failedToCreateEntry:
237229 return " failed to create entry "
238230 case . fileDoesNotExist( let url) :
239231 return " file \( url. path) does not exist "
232+ case . failedToCreateInputStream( let url) :
233+ return " failed to create input stream for \( url. path) "
240234 }
241235 }
242236 }
243237}
238+
239+ extension WriteEntry : @retroactive Encodable {
240+ enum CodingKeys : String , CodingKey {
241+ case path
242+ case fileType
243+ case size
244+ case permissions
245+ case owner
246+ case group
247+ case symlinkTarget
248+ case hardlink
249+ case creationDate
250+ case modificationDate
251+ case contentAccessDate
252+ }
253+
254+ public func encode( to encoder: any Encoder ) throws {
255+ var container = encoder. container ( keyedBy: CodingKeys . self)
256+ try container. encodeIfPresent ( fileType. rawValue, forKey: . fileType)
257+ try container. encodeIfPresent ( permissions, forKey: . permissions)
258+ try container. encodeIfPresent ( path, forKey: . path)
259+ try container. encodeIfPresent ( size, forKey: . size)
260+ try container. encodeIfPresent ( owner, forKey: . owner)
261+ try container. encodeIfPresent ( group, forKey: . group)
262+ try container. encodeIfPresent ( symlinkTarget, forKey: . symlinkTarget)
263+ try container. encodeIfPresent ( hardlink, forKey: . hardlink)
264+ try container. encodeIfPresent ( creationDate, forKey: . creationDate)
265+ try container. encodeIfPresent ( modificationDate, forKey: . modificationDate)
266+ try container. encodeIfPresent ( contentAccessDate, forKey: . contentAccessDate)
267+ }
268+ }
0 commit comments