From b070e9fbf5f2054ad77d9cd79cc448816f3852d2 Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 20 Apr 2023 14:35:46 +0100 Subject: [PATCH 1/2] Add `hasQuarantineAttribute` to `FileSystem` This new function returns `true` if a given path has a quarantine attribute applied if when file system supports this attribute, and returns `false` if such attribute is not applied or it isn't supported. --- Sources/TSCBasic/FileSystem.swift | 16 ++++++++++++++++ Tests/TSCBasicTests/FileSystemTests.swift | 11 +++++++++++ 2 files changed, 27 insertions(+) diff --git a/Sources/TSCBasic/FileSystem.swift b/Sources/TSCBasic/FileSystem.swift index 22d4164a..bd221678 100644 --- a/Sources/TSCBasic/FileSystem.swift +++ b/Sources/TSCBasic/FileSystem.swift @@ -168,6 +168,10 @@ public protocol FileSystem: AnyObject, Sendable { /// Check whether the given path is accessible and writable. func isWritable(_ path: AbsolutePath) -> Bool + /// Returns `true` if a given path has a quarantine attribute applied if when file system supports this attribute. + /// Returns `false` if such attribute is not applied or it isn't supported. + func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool + // FIXME: Actual file system interfaces will allow more efficient access to // more data than just the name here. // @@ -293,6 +297,8 @@ public extension FileSystem { func withLock(on path: AbsolutePath, type: FileLock.LockType, _ body: () throws -> T) throws -> T { throw FileSystemError(.unsupported, path) } + + func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool { false } } /// Concrete FileSystem implementation which communicates with the local file system. @@ -341,6 +347,16 @@ private final class LocalFileSystem: FileSystem { return FileInfo(attrs) } + func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool { +#if os(macOS) + let bufLength = getxattr(path.pathString, "com.apple.quarantine", nil, 0, 0, 0) + + return bufLength > 0 +#else + return false +#endif + } + var currentWorkingDirectory: AbsolutePath? { let cwdStr = FileManager.default.currentDirectoryPath diff --git a/Tests/TSCBasicTests/FileSystemTests.swift b/Tests/TSCBasicTests/FileSystemTests.swift index e3920db4..58d9ff4e 100644 --- a/Tests/TSCBasicTests/FileSystemTests.swift +++ b/Tests/TSCBasicTests/FileSystemTests.swift @@ -860,6 +860,17 @@ class FileSystemTests: XCTestCase { try _testFileSystemFileLock(fileSystem: fs, fileA: fileA, fileB: fileB, lockFile: lockFile) } + func testQuarantineAttribute() throws { + try withTemporaryDirectory(removeTreeOnDeinit: true) { tempDir in + let filePath = tempDir.appending(component: "quarantined") + try localFileSystem.writeFileContents(filePath, bytes: "") + try Process.checkNonZeroExit(args: "xattr", "-w", "com.apple.quarantine", "foo", filePath.pathString) + XCTAssertTrue(localFileSystem.hasQuarantineAttribute(filePath)) + try Process.checkNonZeroExit(args: "xattr", "-d", "com.apple.quarantine", filePath.pathString) + XCTAssertFalse(localFileSystem.hasQuarantineAttribute(filePath)) + } + } + private func _testFileSystemFileLock(fileSystem fs: FileSystem, fileA: AbsolutePath, fileB: AbsolutePath, lockFile: AbsolutePath) throws { // write initial value, since reader may start before writers and files would not exist try fs.writeFileContents(fileA, bytes: "0") From d49d620fdc34507f655214c6f6f4158e7c477b7d Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Thu, 20 Apr 2023 19:29:52 +0100 Subject: [PATCH 2/2] Address PR feedback, fix tests on Linux --- Sources/TSCBasic/FileSystem.swift | 2 +- Tests/TSCBasicTests/FileSystemTests.swift | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/TSCBasic/FileSystem.swift b/Sources/TSCBasic/FileSystem.swift index bd221678..3cd131e1 100644 --- a/Sources/TSCBasic/FileSystem.swift +++ b/Sources/TSCBasic/FileSystem.swift @@ -348,7 +348,7 @@ private final class LocalFileSystem: FileSystem { } func hasQuarantineAttribute(_ path: AbsolutePath) -> Bool { -#if os(macOS) +#if canImport(Darwin) let bufLength = getxattr(path.pathString, "com.apple.quarantine", nil, 0, 0, 0) return bufLength > 0 diff --git a/Tests/TSCBasicTests/FileSystemTests.swift b/Tests/TSCBasicTests/FileSystemTests.swift index 58d9ff4e..95b4910b 100644 --- a/Tests/TSCBasicTests/FileSystemTests.swift +++ b/Tests/TSCBasicTests/FileSystemTests.swift @@ -860,6 +860,7 @@ class FileSystemTests: XCTestCase { try _testFileSystemFileLock(fileSystem: fs, fileA: fileA, fileB: fileB, lockFile: lockFile) } +#if canImport(Darwin) func testQuarantineAttribute() throws { try withTemporaryDirectory(removeTreeOnDeinit: true) { tempDir in let filePath = tempDir.appending(component: "quarantined") @@ -870,6 +871,7 @@ class FileSystemTests: XCTestCase { XCTAssertFalse(localFileSystem.hasQuarantineAttribute(filePath)) } } +#endif private func _testFileSystemFileLock(fileSystem fs: FileSystem, fileA: AbsolutePath, fileB: AbsolutePath, lockFile: AbsolutePath) throws { // write initial value, since reader may start before writers and files would not exist