diff --git a/Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift b/Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift index a1355e78d..47b270c57 100644 --- a/Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift +++ b/Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift @@ -57,7 +57,8 @@ extension _FileManagerImpl { ) throws { #if os(Windows) var bIsDirectory = false - _ = fileManager.fileExists(atPath: destPath, isDirectory: &bIsDirectory) + let absoluteDestPath = URL(filePath: destPath, relativeTo: URL(filePath: path, directoryHint: .notDirectory)).path + _ = fileManager.fileExists(atPath: absoluteDestPath, isDirectory: &bIsDirectory) try path.withNTPathRepresentation { lpSymlinkFileName in try destPath.withFileSystemRepresentation { diff --git a/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift b/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift index a25638ab4..9f5816570 100644 --- a/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift +++ b/Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift @@ -395,9 +395,13 @@ final class FileManagerTests : XCTestCase { func testCreateSymbolicLinkAtPath() throws { try FileManagerPlayground { "foo" + Directory("dir") {} }.test { try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo") XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "bar"), "foo") + + try $0.createSymbolicLink(atPath: "dir_link", withDestinationPath: "dir") + XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir_link"), "dir") XCTAssertThrowsError(try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo")) { XCTAssertEqual(($0 as? CocoaError)?.code, .fileWriteFileExists) @@ -409,6 +413,41 @@ final class FileManagerTests : XCTestCase { XCTAssertEqual(($0 as? CocoaError)?.code, .fileReadUnknown) } } + + try FileManagerPlayground { + Directory("dir") { + Directory("other_dir") { + "file" + } + } + }.test { + // Create a relative symlink to other_dir from within dir (tests windows special dir symlink handling) + try $0.createSymbolicLink(atPath: "dir/link", withDestinationPath: "other_dir") + + // Ensure it is created successfully + XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link"), "other_dir") + XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link"), ["file"]) + + do { + // Second symlink creation with an absolute path + let absolute = URL(filePath: "dir/link2", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path + try $0.createSymbolicLink(atPath: absolute, withDestinationPath: "other_dir") + + // Ensure it is created successfully + XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link2"), "other_dir") + XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link2"), ["file"]) + } + + do { + // And lastly a symlink to an absolute path + let absolute = URL(filePath: "dir/other_dir", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path + try $0.createSymbolicLink(atPath: "dir/link3", withDestinationPath: absolute) + + // Ensure it is created successfully + XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link3"), absolute.withFileSystemRepresentation { String(cString: $0!) }) + XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link3"), ["file"]) + } + } } func testMoveItemAtPathToPath() throws {