@@ -35,6 +35,26 @@ package final class LocalOCILayoutClient: ContentClient {
35
35
return c
36
36
}
37
37
38
+ private func calculateFileDigest( at url: URL ) throws -> SHA256Digest {
39
+ let fileHandle = try FileHandle ( forReadingFrom: url)
40
+ defer {
41
+ try ? fileHandle. close ( )
42
+ }
43
+
44
+ var hasher = SHA256 ( )
45
+ let chunkSize = Int ( getpagesize ( ) ) * 1024
46
+
47
+ while true {
48
+ let chunk = fileHandle. readData ( ofLength: chunkSize)
49
+ if chunk. isEmpty {
50
+ break
51
+ }
52
+ hasher. update ( data: chunk)
53
+ }
54
+
55
+ return hasher. finalize ( )
56
+ }
57
+
38
58
package func fetch< T: Codable > ( name: String , descriptor: Descriptor ) async throws -> T {
39
59
let c = try await self . _fetch ( digest: descriptor. digest)
40
60
return try c. decode ( )
@@ -44,7 +64,8 @@ package final class LocalOCILayoutClient: ContentClient {
44
64
let c = try await self . _fetch ( digest: descriptor. digest)
45
65
let fileManager = FileManager . default
46
66
let filePath = file. absolutePath ( )
47
- if !fileManager. fileExists ( atPath: filePath) {
67
+
68
+ do {
48
69
let src = c. path
49
70
try fileManager. copyItem ( at: src, to: file)
50
71
@@ -53,7 +74,33 @@ package final class LocalOCILayoutClient: ContentClient {
53
74
ProgressEvent ( event: " add-size " , value: fileSize)
54
75
] )
55
76
}
77
+ } catch let error as NSError {
78
+ guard error. code == NSFileWriteFileExistsError else {
79
+ throw error
80
+ }
81
+
82
+ do {
83
+ let expectedDigest = try c. digest ( )
84
+ let existingDigest = try calculateFileDigest ( at: file)
85
+
86
+ guard existingDigest. digestString == expectedDigest. digestString else {
87
+ throw ContainerizationError (
88
+ . internalError,
89
+ message:
90
+ " File \( filePath) exists but contains different content. Expected digest: \( expectedDigest. digestString) , existing digest: \( existingDigest. digestString) "
91
+ )
92
+ }
93
+
94
+ if let progress, let fileSize = fileManager. fileSize ( atPath: filePath) {
95
+ await progress ( [
96
+ ProgressEvent ( event: " add-size " , value: fileSize)
97
+ ] )
98
+ }
99
+ } catch {
100
+ throw error
101
+ }
56
102
}
103
+
57
104
let size = try Int64 ( c. size ( ) )
58
105
let digest = try c. digest ( )
59
106
return ( size, digest)
0 commit comments