1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if FOUNDATION_FRAMEWORK
internal import Foundation_Private.NSPathUtilities
internal import DarwinPrivate.dirhelper
internal import DarwinPrivate.sysdir
internal import _ForSwiftFoundation
#endif
#if canImport(Darwin)
import Darwin.sysdir
private func foundation_sysdir_start_search_path_enumeration(_ directory: UInt, _ domainMask: UInt) -> sysdir_search_path_enumeration_state {
#if FOUNDATION_FRAMEWORK
sysdir_start_search_path_enumeration_private(
sysdir_search_path_directory_t(UInt32(truncatingIfNeeded: directory)),
sysdir_search_path_domain_private_mask_t(rawValue: UInt32(truncatingIfNeeded: domainMask))
)
#else
sysdir_start_search_path_enumeration(
sysdir_search_path_directory_t(UInt32(truncatingIfNeeded: directory)),
sysdir_search_path_domain_mask_t(rawValue: UInt32(truncatingIfNeeded: domainMask))
)
#endif
}
struct _DarwinSearchPathsSequence: Sequence {
let directory: FileManager.SearchPathDirectory
let domainMask: FileManager.SearchPathDomainMask
final class Iterator: IteratorProtocol {
let directory: FileManager.SearchPathDirectory
let domainMask: FileManager.SearchPathDomainMask
private enum State {
case sysdir(sysdir_search_path_enumeration_state)
#if os(macOS) && FOUNDATION_FRAMEWORK
case special(FileManager.SearchPathDomainMask)
#endif
}
private var state: State
init(directory: FileManager.SearchPathDirectory, domainMask: FileManager.SearchPathDomainMask) {
self.directory = directory
self.domainMask = domainMask
switch directory {
#if os(macOS) && FOUNDATION_FRAMEWORK
case .trashDirectory:
state = .special(domainMask.union([.userDomainMask, .localDomainMask]))
case ._homeDirectory, .applicationScriptsDirectory:
state = .special(domainMask.union(.userDomainMask))
#endif
default:
state = .sysdir(foundation_sysdir_start_search_path_enumeration(directory.rawValue, domainMask.rawValue))
}
}
func next() -> String? {
switch state {
case .sysdir(let sysdirState):
return withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { buffer in
let newState = sysdir_get_next_search_path_enumeration(sysdirState, buffer.baseAddress!)
state = .sysdir(newState)
if newState != 0 {
return FileManager.default.string(withFileSystemRepresentation: buffer.baseAddress!, length: strlen(buffer.baseAddress!))
} else {
return nil
}
}
#if os(macOS) && FOUNDATION_FRAMEWORK
case .special(var mask):
defer { state = .special(mask) }
while let currentMask = mask.firstMask {
mask.remove(currentMask)
if let result = _specialFind(directory, in: currentMask) {
return result
}
}
return nil
#endif
}
}
#if os(macOS) && FOUNDATION_FRAMEWORK
private func _specialFindReturn(_ buffer: UnsafeMutableBufferPointer<CChar>) -> String? {
guard buffer.baseAddress!.pointee != 0 else { return nil }
let path = String(cString: buffer.baseAddress!)
// strip trailing slashes because NSPathUtilities doesn't return paths with trailing slashes.
guard let endIndex = path.unicodeScalars.lastIndex(where: { $0 != "/" }) else {
// It's only slashes, so just return a single slash
return "/"
}
return String(path[...endIndex])
}
private func _specialFind(_ directory: FileManager.SearchPathDirectory, in mask: FileManager.SearchPathDomainMask) -> String? {
withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { cpath in
switch (directory, mask) {
case (.trashDirectory, .userDomainMask):
// get the trash relative to the home directory without checking to see if the directory exists
return String.homeDirectoryPath().withFileSystemRepresentation { homePathPtr -> String? in
guard let homePathPtr else { return nil }
if __user_relative_dirname(geteuid(), DIRHELPER_RELATIVE_TRASH, homePathPtr, cpath.baseAddress!, FileManager.MAX_PATH_SIZE) != nil {
var buff = stat()
if lstat(cpath.baseAddress!, &buff) == 0 {
return _specialFindReturn(cpath)?.abbreviatingWithTildeInPath
}
}
return nil
}
case (.trashDirectory, .localDomainMask):
// get the trash on the boot volume without checking to see if the directory exists
if __user_relative_dirname(geteuid(), DIRHELPER_RELATIVE_TRASH, "/", cpath.baseAddress!, FileManager.MAX_PATH_SIZE) != nil {
var buff = stat()
if lstat(cpath.baseAddress!, &buff) == 0 {
return _specialFindReturn(cpath)
}
}
return nil
case (.applicationScriptsDirectory, .userDomainMask):
guard let id = _NSCodeSigningIdentifierForCurrentProcess() else {
return nil
}
return "\("~".replacingTildeWithRealHomeDirectory)/Library/Application Scripts/\(id)"
case (._homeDirectory, .userDomainMask):
return "~"
default:
return nil
}
}
}
#endif
}
func makeIterator() -> Iterator {
Iterator(directory: directory, domainMask: domainMask)
}
}
#if os(macOS) && FOUNDATION_FRAMEWORK
extension String {
internal var replacingTildeWithRealHomeDirectory: String {
guard self == "~" || self.hasPrefix("~/") else {
return self
}
let euid = geteuid()
let trueUid = euid == 0 ? getuid() : euid
guard let name = Platform.name(forUID: trueUid) else {
return self
}
return name.appendingPathComponent(String(self.dropFirst()))
}
}
#endif // os(macOS) && FOUNDATION_FRAMEWORK
#endif // canImport(Darwin)
|