Skip to content

Commit c3f5816

Browse files
authored
Handle the same file name in the fetchBlob method (#258)
With the suggested change, when a file exists, we'll verify whether it has the same content before skipping it.
1 parent 5498087 commit c3f5816

File tree

1 file changed

+48
-1
lines changed

1 file changed

+48
-1
lines changed

Sources/ContainerizationOCI/Client/LocalOCILayoutClient.swift

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,26 @@ package final class LocalOCILayoutClient: ContentClient {
3535
return c
3636
}
3737

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+
3858
package func fetch<T: Codable>(name: String, descriptor: Descriptor) async throws -> T {
3959
let c = try await self._fetch(digest: descriptor.digest)
4060
return try c.decode()
@@ -44,7 +64,8 @@ package final class LocalOCILayoutClient: ContentClient {
4464
let c = try await self._fetch(digest: descriptor.digest)
4565
let fileManager = FileManager.default
4666
let filePath = file.absolutePath()
47-
if !fileManager.fileExists(atPath: filePath) {
67+
68+
do {
4869
let src = c.path
4970
try fileManager.copyItem(at: src, to: file)
5071

@@ -53,7 +74,33 @@ package final class LocalOCILayoutClient: ContentClient {
5374
ProgressEvent(event: "add-size", value: fileSize)
5475
])
5576
}
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+
}
56102
}
103+
57104
let size = try Int64(c.size())
58105
let digest = try c.digest()
59106
return (size, digest)

0 commit comments

Comments
 (0)