FileManager.fileExists(atPath:) should follow symlinks (#859)

This commit is contained in:
Jeremy Schonfeld 2024-08-16 11:19:26 -07:00 committed by GitHub
parent e555c629ba
commit 7242610c89
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 19 additions and 4 deletions

View File

@ -380,12 +380,19 @@ extension _FileManagerImpl {
private func _fileExists(_ path: String) -> (exists: Bool, isDirectory: Bool) {
#if os(Windows)
guard !path.isEmpty else { return (false, false) }
return (try? path.withNTPathRepresentation {
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = .init()
guard GetFileAttributesExW($0, GetFileExInfoStandard, &faAttributes) else {
return (try? path.withNTPathRepresentation { pwszPath in
let handle = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nil)
if handle == INVALID_HANDLE_VALUE {
return (false, false)
}
return (true, faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
defer { CloseHandle(handle) }
var info: BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION()
guard GetFileInformationByHandle(handle, &info) else {
return (false, false)
}
return (true, info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
}) ?? (false, false)
#else
path.withFileSystemRepresentation { rep -> (Bool, Bool) in

View File

@ -571,6 +571,9 @@ final class FileManagerTests : XCTestCase {
"bar"
}
"other"
SymbolicLink("link_to_file", destination: "other")
SymbolicLink("link_to_dir", destination: "dir")
SymbolicLink("link_to_nonexistent", destination: "does_not_exist")
}.test {
#if FOUNDATION_FRAMEWORK
var isDir: ObjCBool = false
@ -591,7 +594,12 @@ final class FileManagerTests : XCTestCase {
XCTAssertTrue(isDirBool())
XCTAssertTrue($0.fileExists(atPath: "other", isDirectory: &isDir))
XCTAssertFalse(isDirBool())
XCTAssertTrue($0.fileExists(atPath: "link_to_file", isDirectory: &isDir))
XCTAssertFalse(isDirBool())
XCTAssertTrue($0.fileExists(atPath: "link_to_dir", isDirectory: &isDir))
XCTAssertTrue(isDirBool())
XCTAssertFalse($0.fileExists(atPath: "does_not_exist"))
XCTAssertFalse($0.fileExists(atPath: "link_to_nonexistent"))
}
}