swift-foundation/Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift
Jeremy Schonfeld 33856a556d
(120741818) Port FileManager to swift-foundation
* (120741818) Port FileManager to swift-foundation

* (120741818) Fix linux test failures

* (120741818) Fix build failures
2024-02-09 15:03:43 -08:00

114 lines
3.9 KiB
Swift

//===----------------------------------------------------------------------===//
//
// 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 canImport(Darwin)
import Darwin
#elseif canImport(Glibc)
import Glibc
#endif
extension _FileManagerImpl {
func createSymbolicLink(
at url: URL,
withDestinationURL destURL: URL
) throws {
guard url.isFileURL else {
throw CocoaError.errorWithFilePath(.fileReadUnsupportedScheme, url)
}
// If there's no scheme, then this is probably a relative URL.
if destURL.scheme != nil && !destURL.isFileURL {
throw CocoaError.errorWithFilePath(.fileWriteUnsupportedScheme, destURL)
}
let path = url.path
let destPath = destURL.path
guard !path.isEmpty else {
throw CocoaError.errorWithFilePath(.fileNoSuchFile, url)
}
guard !destPath.isEmpty else {
throw CocoaError.errorWithFilePath(.fileNoSuchFile, destURL)
}
try createSymbolicLink(atPath: path, withDestinationPath: destPath)
}
func createSymbolicLink(
atPath path: String,
withDestinationPath destPath: String
) throws {
try fileManager.withFileSystemRepresentation(for: path) { srcRep in
guard let srcRep else {
throw CocoaError.errorWithFilePath(.fileReadUnknown, path)
}
try fileManager.withFileSystemRepresentation(for: destPath) { destRep in
guard let destRep else {
throw CocoaError.errorWithFilePath(.fileReadUnknown, destPath)
}
if symlink(destRep, srcRep) != 0 {
throw CocoaError.errorWithFilePath(path, errno: errno, reading: false)
}
}
}
}
func linkItem(
at srcURL: URL,
to dstURL: URL
) throws {
guard srcURL.isFileURL else {
throw CocoaError.errorWithFilePath(.fileReadUnsupportedScheme, srcURL)
}
guard dstURL.isFileURL else {
throw CocoaError.errorWithFilePath(.fileWriteUnsupportedScheme, dstURL)
}
let srcPath = srcURL.path
let dstPath = dstURL.path
guard !srcPath.isEmpty else {
throw CocoaError.errorWithFilePath(.fileNoSuchFile, srcURL)
}
guard !dstPath.isEmpty else {
throw CocoaError.errorWithFilePath(.fileNoSuchFile, dstURL)
}
try linkItem(atPath: srcPath, toPath: dstPath)
}
func linkItem(
atPath srcPath: String,
toPath dstPath: String
) throws {
try _FileOperations.linkFile(srcPath, to: dstPath, with: fileManager)
}
func destinationOfSymbolicLink(atPath path: String) throws -> String {
try fileManager.withFileSystemRepresentation(for: path) { rep in
guard let rep else {
throw CocoaError.errorWithFilePath(.fileReadUnknown, path)
}
return try withUnsafeTemporaryAllocation(of: CChar.self, capacity: FileManager.MAX_PATH_SIZE) { buffer in
let charsReturned = readlink(rep, buffer.baseAddress!, FileManager.MAX_PATH_SIZE)
guard charsReturned >= 0 else {
throw CocoaError.errorWithFilePath(path, errno: errno, reading: true)
}
return fileManager.string(withFileSystemRepresentation: buffer.baseAddress!, length: charsReturned)
}
}
}
}