Skip to content

Commit d1da0f7

Browse files
authored
Fix windows creation of relative symlinks to directories (#931)
* Fix windows creation of relative symlinks to directories * Add additional unit tests * Fix windows test failure
1 parent 8059ee7 commit d1da0f7

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
@@ -59,7 +59,8 @@ extension _FileManagerImpl {
5959
) throws {
6060
#if os(Windows)
6161
var bIsDirectory = false
62-
_ = fileManager.fileExists(atPath: destPath, isDirectory: &bIsDirectory)
62+
let absoluteDestPath = URL(filePath: destPath, relativeTo: URL(filePath: path, directoryHint: .notDirectory)).path
63+
_ = fileManager.fileExists(atPath: absoluteDestPath, isDirectory: &bIsDirectory)
6364

6465
try path.withNTPathRepresentation { lpSymlinkFileName in
6566
try destPath.withFileSystemRepresentation {

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,13 @@ final class FileManagerTests : XCTestCase {
412412
func testCreateSymbolicLinkAtPath() throws {
413413
try FileManagerPlayground {
414414
"foo"
415+
Directory("dir") {}
415416
}.test {
416417
try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo")
417418
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "bar"), "foo")
419+
420+
try $0.createSymbolicLink(atPath: "dir_link", withDestinationPath: "dir")
421+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir_link"), "dir")
418422

419423
XCTAssertThrowsError(try $0.createSymbolicLink(atPath: "bar", withDestinationPath: "foo")) {
420424
XCTAssertEqual(($0 as? CocoaError)?.code, .fileWriteFileExists)
@@ -426,6 +430,41 @@ final class FileManagerTests : XCTestCase {
426430
XCTAssertEqual(($0 as? CocoaError)?.code, .fileReadUnknown)
427431
}
428432
}
433+
434+
try FileManagerPlayground {
435+
Directory("dir") {
436+
Directory("other_dir") {
437+
"file"
438+
}
439+
}
440+
}.test {
441+
// Create a relative symlink to other_dir from within dir (tests windows special dir symlink handling)
442+
try $0.createSymbolicLink(atPath: "dir/link", withDestinationPath: "other_dir")
443+
444+
// Ensure it is created successfully
445+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link"), "other_dir")
446+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link"), ["file"])
447+
448+
do {
449+
// Second symlink creation with an absolute path
450+
let absolute = URL(filePath: "dir/link2", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path
451+
try $0.createSymbolicLink(atPath: absolute, withDestinationPath: "other_dir")
452+
453+
// Ensure it is created successfully
454+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link2"), "other_dir")
455+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link2"), ["file"])
456+
}
457+
458+
do {
459+
// And lastly a symlink to an absolute path
460+
let absolute = URL(filePath: "dir/other_dir", relativeTo: URL(filePath: $0.currentDirectoryPath, directoryHint: .isDirectory)).path
461+
try $0.createSymbolicLink(atPath: "dir/link3", withDestinationPath: absolute)
462+
463+
// Ensure it is created successfully
464+
XCTAssertEqual(try $0.destinationOfSymbolicLink(atPath: "dir/link3"), absolute.withFileSystemRepresentation { String(cString: $0!) })
465+
XCTAssertEqual(try $0.contentsOfDirectory(atPath: "dir/link3"), ["file"])
466+
}
467+
}
429468
}
430469

431470
func testMoveItemAtPathToPath() throws {

0 commit comments

Comments
 (0)