WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Sources/FoundationEssentials/FileManager/FileManager+Files.swift
Original file line number Diff line number Diff line change
Expand Up @@ -522,21 +522,21 @@ extension _FileManagerImpl {

private func _extendedAttributes(at path: UnsafePointer<CChar>, followSymlinks: Bool) throws -> [String : Data]? {
#if canImport(Darwin)
var size = listxattr(path, nil, 0, 0)
var size = listxattr(path, nil, 0, followSymlinks ? 0 : XATTR_NOFOLLOW)
#elseif os(FreeBSD)
var size = (followSymlinks ? extattr_list_file : extattr_list_link)(path, EXTATTR_NAMESPACE_USER, nil, 0)
#else
var size = listxattr(path, nil, 0)
var size = followSymlinks ? listxattr(path, nil, 0) : llistxattr(path, nil, 0)
#endif
guard size > 0 else { return nil }
let keyList = UnsafeMutableBufferPointer<CChar>.allocate(capacity: size)
defer { keyList.deallocate() }
#if canImport(Darwin)
size = listxattr(path, keyList.baseAddress!, size, 0)
size = listxattr(path, keyList.baseAddress!, size, followSymlinks ? 0 : XATTR_NOFOLLOW)
#elseif os(FreeBSD)
size = (followSymlinks ? extattr_list_file : extattr_list_link)(path, EXTATTR_NAMESPACE_USER, nil, 0)
size = (followSymlinks ? extattr_list_file : extattr_list_link)(path, EXTATTR_NAMESPACE_USER, keyList.baseAddress!, size)
#else
size = listxattr(path, keyList.baseAddress!, size)
size = followSymlinks ? listxattr(path, keyList.baseAddress!, size) : llistxattr(path, keyList.baseAddress!, size)
#endif
guard size > 0 else { return nil }

Expand All @@ -553,7 +553,7 @@ extension _FileManagerImpl {
}
#endif

if let value = try _extendedAttribute(current, at: path, followSymlinks: false) {
if let value = try _extendedAttribute(current, at: path, followSymlinks: followSymlinks) {
extendedAttrs[currentKey] = value
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,15 +193,15 @@ extension _FileManagerImpl {
#else
var result: Int32
if followSymLinks {
result = lsetxattr(path, key, buffer.baseAddress!, buffer.count, 0)
} else {
result = setxattr(path, key, buffer.baseAddress!, buffer.count, 0)
} else {
result = lsetxattr(path, key, buffer.baseAddress!, buffer.count, 0)
}
#endif

#if os(macOS) && FOUNDATION_FRAMEWORK
// if setxaddr failed and its a permission error for a sandbox app trying to set quaratine attribute, ignore it since its not
// permitted, the attribute will be put on the file by the quaratine MAC hook
// if setxattr failed and its a permission error for a sandbox app trying to set quarantine attribute, ignore it since its not
// permitted, the attribute will be put on the file by the quarantine MAC hook
if result == -1 && errno == EPERM && _xpc_runtime_is_app_sandboxed() && strcmp(key, "com.apple.quarantine") == 0 {
return
}
Expand Down
54 changes: 54 additions & 0 deletions Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1046,6 +1046,60 @@ private struct FileManagerTests {
}
}

// Extended attributes are not supported on all platforms
#if !os(Windows) && !os(WASI) && !os(OpenBSD) && !canImport(Android)
@Test func extendedAttributesOnSymlinks() async throws {
let xattrKey = FileAttributeKey("NSFileExtendedAttributes")
#if os(Linux)
// Linux requires the user.* namespace prefix for regular files
let attrName = "user.swift.foundation.symlinktest"
#else
let attrName = "org.swift.foundation.symlinktest"
#endif
let attrValue = Data([0xAA, 0xBB, 0xCC])
let attrValue2 = Data([0xDD, 0xEE, 0xFF])

try await FilePlayground {
File("target", contents: Data("payload".utf8))
SymbolicLink("link", destination: "target")
}.test { fileManager in
// First, validate that reading the attribute from the link does not read the value from the target
do {
try fileManager.setAttributes([xattrKey: [attrName: attrValue]], ofItemAtPath: "target")
let targetAttrs = try fileManager.attributesOfItem(atPath: "target")
let targetXAttrs = targetAttrs[xattrKey] as? [String: Data]
#expect(targetXAttrs?[attrName] == attrValue)

let linkAttrs = try fileManager.attributesOfItem(atPath: "link")
let linkXAttrs = linkAttrs[xattrKey] as? [String: Data]
#expect(linkXAttrs?[attrName] == nil)
}

// Attempt to set xattrs on the symlink
#if os(Linux)
// On Linux, user xattrs cannot be set on symlinks
#expect(throws: CocoaError.self) {
try fileManager.setAttributes([xattrKey: [attrName: attrValue2]], ofItemAtPath: "link")
}
let expectedValue: Data? = nil
#else
try fileManager.setAttributes([xattrKey: [attrName: attrValue2]], ofItemAtPath: "link")
let expectedValue: Data? = attrValue2
#endif

// Ensure that reading back the xattr of the link produces the expected value
let linkAttrs = try fileManager.attributesOfItem(atPath: "link")
let linkXAttrs = linkAttrs[xattrKey] as? [String: Data]
#expect(linkXAttrs?[attrName] == expectedValue)

// Ensure that setting the xattr on the link did not set the xattr on the target
let targetAttrs = try fileManager.attributesOfItem(atPath: "target")
let targetXAttrs = targetAttrs[xattrKey] as? [String: Data]
#expect(targetXAttrs?[attrName] == attrValue)
}
}
#endif

#if !canImport(Darwin) || os(macOS)
@Test func currentUserHomeDirectory() async throws {
let userName = ProcessInfo.processInfo.userName
Expand Down