Skip to content

Commit fe5c618

Browse files
authored
Fix windows creation of relative symlinks to directories (#931) (#941)
* Fix windows creation of relative symlinks to directories * Add additional unit tests * Fix windows test failure
1 parent 402b90e commit fe5c618

File tree

2 files changed

+41
-1
lines changed

2 files changed

+41
-1
lines changed

Sources/FoundationEssentials/FileManager/FileManager+SymbolicLinks.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ extension _FileManagerImpl {
5757
) throws {
5858
#if os(Windows)
5959
var bIsDirectory = false
60-
_ = fileManager.fileExists(atPath: destPath, isDirectory: &bIsDirectory)
60+
let absoluteDestPath = URL(filePath: destPath, relativeTo: URL(filePath: path, directoryHint: .notDirectory)).path
61+
_ = fileManager.fileExists(atPath: absoluteDestPath, isDirectory: &bIsDirectory)
6162

6263
try path.withNTPathRepresentation { lpSymlinkFileName in
6364
try destPath.withFileSystemRepresentation {

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,13 @@ final class FileManagerTests : XCTestCase {
395395
func testCreateSymbolicLinkAtPath() throws {
396396
try FileManagerPlayground {
397397
"foo"
398+
Directory("dir") {}
398399
}.test {
399400
try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo")
400401
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "bar"), "foo")
402+
403+
try $0.createSymbolicLink(atPath: "dir_link", withDestinationPath: "dir")
404+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir_link"), "dir")
401405

402406
XCTAssertThrowsError(try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo")) {
403407
XCTAssertEqual(($0 as? CocoaError)?.code, .fileWriteFileExists)
@@ -409,6 +413,41 @@ final class FileManagerTests : XCTestCase {
409413
XCTAssertEqual(($0 as? CocoaError)?.code, .fileReadUnknown)
410414
}
411415
}
416+
417+
try FileManagerPlayground {
418+
Directory("dir") {
419+
Directory("other_dir") {
420+
"file"
421+
}
422+
}
423+
}.test {
424+
// Create a relative symlink to other_dir from within dir (tests windows special dir symlink handling)
425+
try $0.createSymbolicLink(atPath: "dir/link", withDestinationPath: "other_dir")
426+
427+
// Ensure it is created successfully
428+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link"), "other_dir")
429+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link"), ["file"])
430+
431+
do {
432+
// Second symlink creation with an absolute path
433+
let absolute = URL(filePath: "dir/link2", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path
434+
try $0.createSymbolicLink(atPath: absolute, withDestinationPath: "other_dir")
435+
436+
// Ensure it is created successfully
437+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link2"), "other_dir")
438+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link2"), ["file"])
439+
}
440+
441+
do {
442+
// And lastly a symlink to an absolute path
443+
let absolute = URL(filePath: "dir/other_dir", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path
444+
try $0.createSymbolicLink(atPath: "dir/link3", withDestinationPath: absolute)
445+
446+
// Ensure it is created successfully
447+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link3"), absolute.withFileSystemRepresentation { String(cString: $0!) })
448+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link3"), ["file"])
449+
}
450+
}
412451
}
413452

414453
func testMoveItemAtPathToPath() throws {

0 commit comments

Comments
 (0)