From 7963ebc2377a0d8cc42a40e020c3448ee0fb1a3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20B=C3=BCgling?= Date: Wed, 2 Aug 2023 13:42:25 -0700 Subject: [PATCH] [FileSystem] Add API for obtaining item replacement directory (#427) This is used by many Foundation methods that take an `atomically` parameter and we need to expose this in order to allow sandboxes processes to write to it. --- Sources/TSCBasic/FileSystem.swift | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sources/TSCBasic/FileSystem.swift b/Sources/TSCBasic/FileSystem.swift index bebc0475..800387a5 100644 --- a/Sources/TSCBasic/FileSystem.swift +++ b/Sources/TSCBasic/FileSystem.swift @@ -196,6 +196,10 @@ public protocol FileSystem: Sendable { /// Check whether the given path is accessible and writable. func isWritable(_ path: AbsolutePath) -> Bool + /// Returns any known item replacement directories for a given path. These may be used by platform-specific + /// libraries to handle atomic file system operations, such as deletion. + func itemReplacementDirectories(for path: AbsolutePath) throws -> [AbsolutePath] + @available(*, deprecated, message: "use `hasAttribute(_:_:)` instead") func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool @@ -346,6 +350,8 @@ public extension FileSystem { func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool { false } func hasAttribute(_ name: FileSystemAttribute, _ path: AbsolutePath) -> Bool { false } + + func itemReplacementDirectories(for path: AbsolutePath) throws -> [AbsolutePath] { [] } } /// Concrete FileSystem implementation which communicates with the local file system. @@ -616,6 +622,13 @@ private struct LocalFileSystem: FileSystem { ) async throws -> T { try await FileLock.withLock(fileToLock: path, type: type, body: body) } + + func itemReplacementDirectories(for path: AbsolutePath) throws -> [AbsolutePath] { + let result = try FileManager.default.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: path.asURL, create: false) + let path = try AbsolutePath(validating: result.path) + // Foundation returns a path that is unique every time, so we return both that path, as well as its parent. + return [path, path.parentDirectory] + } } /// Concrete FileSystem implementation which simulates an empty disk.