Skip to content

Commit d3d7d21

Browse files
authored
Adds FileDescriptor-based enumerate(). (#746)
- Closes #745. - Facilitates TOCTOU-safe recursion over directory contents. - Replace FileDescriptor extensions with a static utility type to prevent potential namespacing issues as this project and Swift evolve.
1 parent c8fe3bb commit d3d7d21

4 files changed

Lines changed: 599 additions & 253 deletions

File tree

Sources/ContainerizationArchive/ArchiveReader.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,9 +346,9 @@ extension ArchiveReader {
346346
do {
347347
switch type {
348348
case .regular:
349-
try rootFileDescriptor.mkdirSecure(relativePath, makeIntermediates: true) { fd in
349+
try FileDescriptorOps.mkdir(rootFileDescriptor, relativePath, makeIntermediates: true) { fd in
350350
// Remove existing entry if present (mimics containerd's "last entry wins" behavior)
351-
try? fd.unlinkRecursiveSecure(filename: lastComponent)
351+
try? FileDescriptorOps.unlinkRecursive(fd, filename: lastComponent)
352352

353353
// Open file for writing using openat with O_NOFOLLOW to prevent TOC-TOU attacks
354354
let fileMode = entry.permissions & 0o777 // Mask to permission bits only
@@ -362,17 +362,17 @@ extension ArchiveReader {
362362
setFileAttributes(fd: fileFd, entry: entry)
363363
}
364364
case .directory:
365-
try rootFileDescriptor.mkdirSecure(memberPath, makeIntermediates: true) { fd in
365+
try FileDescriptorOps.mkdir(rootFileDescriptor, memberPath, makeIntermediates: true) { fd in
366366
setFileAttributes(fd: fd.rawValue, entry: entry)
367367
}
368368
case .symbolicLink:
369369
guard let targetPath = (entry.symlinkTarget.map { FilePath($0) }) else {
370370
return false
371371
}
372372
var symlinkCreated = false
373-
try rootFileDescriptor.mkdirSecure(relativePath, makeIntermediates: true) { fd in
373+
try FileDescriptorOps.mkdir(rootFileDescriptor, relativePath, makeIntermediates: true) { fd in
374374
// Remove existing entry if present (mimics containerd's "last entry wins" behavior)
375-
try? fd.unlinkRecursiveSecure(filename: lastComponent)
375+
try? FileDescriptorOps.unlinkRecursive(fd, filename: lastComponent)
376376

377377
guard symlinkat(targetPath.string, fd.rawValue, lastComponent.string) == 0 else {
378378
throw ArchiveError.failedToExtractArchive("failed to create symlink: \(targetPath) <- \(memberPath)")
@@ -385,7 +385,7 @@ extension ArchiveReader {
385385
}
386386

387387
return true
388-
} catch let error as SecurePathError {
388+
} catch let error as FileDescriptorOps.Error {
389389
// Just reject path validation errors, don't fail the extraction
390390
switch error {
391391
case .systemError:

Sources/ContainerizationOS/FileDescriptor+SecurePath.swift

Lines changed: 0 additions & 218 deletions
This file was deleted.

0 commit comments

Comments
 (0)