Skip to content

Commit 7242610

Browse files
authored
FileManager.fileExists(atPath:) should follow symlinks (#859)
1 parent e555c62 commit 7242610

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
@@ -380,12 +380,19 @@ extension _FileManagerImpl {
380380
private func _fileExists(_ path: String) -> (exists: Bool, isDirectory: Bool) {
381381
#if os(Windows)
382382
guard !path.isEmpty else { return (false, false) }
383-
return (try? path.withNTPathRepresentation {
384-
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = .init()
385-
guard GetFileAttributesExW($0, GetFileExInfoStandard, &faAttributes) else {
383+
return (try? path.withNTPathRepresentation { pwszPath in
384+
let handle = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nil)
385+
if handle == INVALID_HANDLE_VALUE {
386+
return (false, false)
387+
}
388+
defer { CloseHandle(handle) }
389+
390+
var info: BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION()
391+
guard GetFileInformationByHandle(handle, &info) else {
386392
return (false, false)
387393
}
388-
return (true, faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
394+
395+
return (true, info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
389396
}) ?? (false, false)
390397
#else
391398
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)