Skip to content

Commit 318ea46

Browse files
authored
FileManager.fileExists(atPath:) should follow symlinks (#859) (#866)
1 parent 0560549 commit 318ea46

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

Sources/FoundationEssentials/FileManager/FileManager+Files.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,19 @@ extension _FileManagerImpl {
376376
private func _fileExists(_ path: String) -> (exists: Bool, isDirectory: Bool) {
377377
#if os(Windows)
378378
guard !path.isEmpty else { return (false, false) }
379-
return (try? path.withNTPathRepresentation {
380-
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = .init()
381-
guard GetFileAttributesExW($0, GetFileExInfoStandard, &faAttributes) else {
379+
return (try? path.withNTPathRepresentation { pwszPath in
380+
let handle = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nil)
381+
if handle == INVALID_HANDLE_VALUE {
382+
return (false, false)
383+
}
384+
defer { CloseHandle(handle) }
385+
386+
var info: BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION()
387+
guard GetFileInformationByHandle(handle, &info) else {
382388
return (false, false)
383389
}
384-
return (true, faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
390+
391+
return (true, info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
385392
}) ?? (false, false)
386393
#else
387394
path.withFileSystemRepresentation { rep -> (Bool, Bool) in

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,9 @@ final class FileManagerTests : XCTestCase {
571571
"bar"
572572
}
573573
"other"
574+
SymbolicLink("link_to_file", destination: "other")
575+
SymbolicLink("link_to_dir", destination: "dir")
576+
SymbolicLink("link_to_nonexistent", destination: "does_not_exist")
574577
}.test {
575578
#if FOUNDATION_FRAMEWORK
576579
var isDir: ObjCBool = false
@@ -591,7 +594,12 @@ final class FileManagerTests : XCTestCase {
591594
XCTAssertTrue(isDirBool())
592595
XCTAssertTrue($0.fileExists(atPath: "other", isDirectory: &isDir))
593596
XCTAssertFalse(isDirBool())
597+
XCTAssertTrue($0.fileExists(atPath: "link_to_file", isDirectory: &isDir))
598+
XCTAssertFalse(isDirBool())
599+
XCTAssertTrue($0.fileExists(atPath: "link_to_dir", isDirectory: &isDir))
600+
XCTAssertTrue(isDirBool())
594601
XCTAssertFalse($0.fileExists(atPath: "does_not_exist"))
602+
XCTAssertFalse($0.fileExists(atPath: "link_to_nonexistent"))
595603
}
596604
}
597605

0 commit comments

Comments
 (0)