Skip to content

Commit 1e3f4fa

Browse files
committed
FileManager: lsetxattr and setxattr are swapped
The if statement appears inverted: setxattr follows simlinks: lsetxattr does not.
1 parent 439b692 commit 1e3f4fa

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

Sources/FoundationEssentials/FileManager/FileManager+Utilities.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,15 +193,15 @@ extension _FileManagerImpl {
193193
#else
194194
var result: Int32
195195
if followSymLinks {
196-
result = lsetxattr(path, key, buffer.baseAddress!, buffer.count, 0)
197-
} else {
198196
result = setxattr(path, key, buffer.baseAddress!, buffer.count, 0)
197+
} else {
198+
result = lsetxattr(path, key, buffer.baseAddress!, buffer.count, 0)
199199
}
200200
#endif
201201

202202
#if os(macOS) && FOUNDATION_FRAMEWORK
203-
// if setxaddr failed and its a permission error for a sandbox app trying to set quaratine attribute, ignore it since its not
204-
// permitted, the attribute will be put on the file by the quaratine MAC hook
203+
// if setxattr failed and its a permission error for a sandbox app trying to set quarantine attribute, ignore it since its not
204+
// permitted, the attribute will be put on the file by the quarantine MAC hook
205205
if result == -1 && errno == EPERM && _xpc_runtime_is_app_sandboxed() && strcmp(key, "com.apple.quarantine") == 0 {
206206
return
207207
}

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,43 @@ private struct FileManagerTests {
10461046
}
10471047
}
10481048

1049+
@Test func extendedAttributesDoNotFollowSymlinksWhenSetting() async throws {
1050+
#if os(Windows) || os(WASI) || os(OpenBSD) || canImport(Android)
1051+
throw Skip("Extended attributes not supported on this platform")
1052+
#else
1053+
let xattrKey = FileAttributeKey("NSFileExtendedAttributes")
1054+
#if canImport(Darwin)
1055+
let attrName = "com.swiftfoundation.symlinktest"
1056+
#elseif os(Linux)
1057+
// Linux requires the user.* namespace prefix for regular files
1058+
let attrName = "user.swiftfoundation.symlinktest"
1059+
#else
1060+
let attrName = "swiftfoundation.symlinktest"
1061+
#endif
1062+
let attrValue = Data([0xAA, 0xBB, 0xCC])
1063+
1064+
try await FilePlayground {
1065+
File("target", contents: Data("payload".utf8))
1066+
SymbolicLink("link", destination: "target")
1067+
}.test { fileManager in
1068+
do {
1069+
try fileManager.setAttributes([xattrKey: [attrName: attrValue]], ofItemAtPath: "link")
1070+
} catch let error as CocoaError where error.code == .featureUnsupported {
1071+
throw Skip("Extended attributes not supported on this filesystem: \(error)")
1072+
}
1073+
1074+
let linkAttrs = try fileManager.attributesOfItem(atPath: "link")
1075+
let targetAttrs = try fileManager.attributesOfItem(atPath: "target")
1076+
1077+
let linkXattrs = linkAttrs[xattrKey] as? [String : Data]
1078+
let targetXattrs = targetAttrs[xattrKey] as? [String : Data]
1079+
1080+
#expect(linkXattrs?[attrName] == attrValue, "xattr should be applied to the symlink itself")
1081+
#expect(targetXattrs?[attrName] == nil, "setAttributes must not follow symlinks when setting extended attributes")
1082+
}
1083+
#endif
1084+
}
1085+
10491086
#if !canImport(Darwin) || os(macOS)
10501087
@Test func currentUserHomeDirectory() async throws {
10511088
let userName = ProcessInfo.processInfo.userName

0 commit comments

Comments
 (0)