30 lines
956 B
Swift
30 lines
956 B
Swift
import Foundation
|
|
|
|
enum RsyncLocator {
|
|
static let candidates = [
|
|
"/opt/homebrew/bin/rsync",
|
|
"/usr/local/bin/rsync",
|
|
"/usr/bin/rsync"
|
|
]
|
|
|
|
static func locate() -> String {
|
|
candidates.first(where: isTrustedExecutableCandidate) ?? "/usr/bin/rsync"
|
|
}
|
|
|
|
static func isTrustedExecutableCandidate(_ path: String) -> Bool {
|
|
let manager = FileManager.default
|
|
guard manager.isExecutableFile(atPath: path) else { return false }
|
|
|
|
let resolved = URL(fileURLWithPath: path).resolvingSymlinksInPath().path
|
|
var isDirectory: ObjCBool = false
|
|
guard manager.fileExists(atPath: resolved, isDirectory: &isDirectory), !isDirectory.boolValue else { return false }
|
|
|
|
do {
|
|
let attributes = try manager.attributesOfItem(atPath: resolved)
|
|
return attributes[.type] as? FileAttributeType == .typeRegular
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
}
|