TeraMediaProcessUse.swift (2905B)
1 import Darwin 2 import Foundation 3 import RadrootsKit 4 5 /// Records admission before underlying work can outlive a caller or runtime. 6 /// The marker deliberately survives shutdown, cancellation and failed creation. 7 /// It is local coordination evidence, never a portable ownership database. 8 enum TeraMediaProcessUse { 9 static let directory = ".tera_media_use" 10 11 static func admit(applicationSupportDirectory: String) throws -> RadrootsFileUseReservation { 12 let parts = applicationSupportDirectory.split(separator: "/") 13 guard applicationSupportDirectory.hasPrefix("/"), !applicationSupportDirectory.utf8.contains(0), 14 !parts.isEmpty, parts.allSatisfy({ $0 != "." && $0 != ".." }) 15 else { throw RadrootsAppleFileError.invalidRequest } 16 return try admit(root: URL(fileURLWithPath: applicationSupportDirectory, isDirectory: true)) 17 } 18 19 static func admit(root: URL) throws -> RadrootsFileUseReservation { 20 guard let use = try RadrootsAppleFileMaintenance(root: root).reserveUse() else { 21 throw RadrootsAppleFileError.transientFailure 22 } 23 let roots = try RadrootsAppleFileRoots( 24 appIdentifier: "tera.media.use", dataRoot: root, cacheRoot: root, temporaryRoot: root 25 ) 26 let pid = getpid() 27 let file = RadrootsFileReference(scope: .data, relativePath: "\(directory)/\(pid)") 28 try RadrootsAppleFileAccess(roots: roots).write(.inline(Data("tera.media.use.v1 \(pid)\n".utf8)), to: file) 29 try use.validate() 30 return use 31 } 32 33 /// Must be called under the exclusive reservation. ESRCH is the only admitted 34 /// absence observation. PID reuse and permission failures conservatively retain. 35 static func hasNoLiveUsers( 36 roots: RadrootsAppleFileRoots, 37 scan: RadrootsFileMaintenanceScan, 38 remaining: inout Int, 39 isAbsent: (Int32) -> Bool = definitelyAbsent 40 ) throws -> Bool { 41 let access = RadrootsAppleFileAccess(roots: roots) 42 while remaining > 0 { 43 let page = try scan.next(limit: min(64, remaining)) 44 remaining -= page.scannedEntries 45 for entry in page.entries { 46 guard entry.kind == .regularFile, entry.sizeBytes > 0, entry.sizeBytes <= 64, 47 let pid = Int32(entry.name), pid > 0, String(pid) == entry.name 48 else { return false } 49 let file = RadrootsFileReference(scope: .data, relativePath: "\(directory)/\(entry.name)") 50 guard case let .inline(data) = try access.read(file, mode: .inline(maxBytes: 64)), 51 data == Data("tera.media.use.v1 \(pid)\n".utf8), isAbsent(pid) 52 else { return false } 53 // Never reuse a marker after a conditional-unlink identity mismatch. 54 guard try scan.remove(entry) else { return false } 55 } 56 if page.reachedEnd { 57 return true 58 } 59 } 60 return false 61 } 62 63 private static func definitelyAbsent(_ pid: Int32) -> Bool { 64 let result = Darwin.kill(pid, 0) 65 return result == -1 && errno == ESRCH 66 } 67 }