From 32a44e56dcd606ab8847968184b45b0b6e0a9358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20M=C3=B6sch?= Date: Sat, 8 Nov 2025 15:01:43 +0100 Subject: [PATCH] Follow symlinks to reach target file --- Sources/Swiftly/Unlink.swift | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Sources/Swiftly/Unlink.swift b/Sources/Swiftly/Unlink.swift index 02d820ca..d34c6902 100644 --- a/Sources/Swiftly/Unlink.swift +++ b/Sources/Swiftly/Unlink.swift @@ -92,8 +92,7 @@ extension SwiftlyCommand { continue } - let potentialProxyPath = swiftlyBinDir / file - if let linkTarget = try? await fs.readlink(atPath: potentialProxyPath), linkTarget == proxyTo { + if await (swiftlyBinDir / file).linksTo(proxyTo) { return true } } @@ -101,3 +100,27 @@ extension SwiftlyCommand { return false } } + +extension FilePath { + fileprivate func linksTo(_ other: FilePath) async -> Bool { + var path = self + var jumps = 0 + while jumps < 10 { // More than 10 jumps is probably a symlink loop. + if path == other { + return true + } + jumps += 1 + do { + let jumpTarget = try await fs.readlink(atPath: path) + path = if jumpTarget.isAbsolute { + jumpTarget + } else { + path.parent.pushing(jumpTarget).lexicallyNormalized() + } + } catch { + break + } + } + return false + } +}