Skip to content

Commit d5be9a4

Browse files
committed
FoundationEssentials: add type to the file attributes on Windows
Get the file type using the Win32 APIs and wire that into the attribute dictionary.
1 parent f657181 commit d5be9a4

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

Sources/FoundationEssentials/FileManager/FileManager+Files.swift

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,20 +531,38 @@ extension _FileManagerImpl {
531531
throw CocoaError.errorWithFilePath(path, win32: GetLastError(), reading: true)
532532
}
533533

534+
let hFile = CreateFileW(pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nil, OPEN_EXISTING, 0, nil)
535+
if hFile == INVALID_HANDLE_VALUE {
536+
throw CocoaError.errorWithFilePath(path, win32: GetLastError(), reading: true)
537+
}
538+
defer { CloseHandle(hFile) }
539+
540+
let dwFileType = GetFileType(hFile)
541+
let fatType: FileAttributeType = switch (dwFileType) {
542+
case FILE_TYPE_CHAR: FileAttributeType.typeCharacterSpecial
543+
case FILE_TYPE_DISK:
544+
faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
545+
? FileAttributeType.typeDirectory
546+
: FileAttributeType.typeRegular
547+
case FILE_TYPE_PIPE: FileAttributeType.typeSocket
548+
case FILE_TYPE_UNKNOWN: FileAttributeType.typeUnknown
549+
default: FileAttributeType.typeUnknown
550+
}
551+
534552
let size: UInt64 = (UInt64(faAttributes.nFileSizeHigh) << 32) | UInt64(faAttributes.nFileSizeLow)
535553
let creation: Date = Date(timeIntervalSince1970: faAttributes.ftCreationTime.timeIntervalSince1970)
536554
let modification: Date = Date(timeIntervalSince1970: faAttributes.ftLastWriteTime.timeIntervalSince1970)
537555
return [
538556
.size: _writeFileAttributePrimitive(size, as: UInt.self),
539557
.modificationDate: modification,
540558
.creationDate: creation,
559+
.type: fatType,
541560

542561
// TODO(compnerd) support these attributes, remapping the Windows semantics...
543562
// .posixPermissions: ...,
544563
// .referenceCount: ...,
545564
// .systemNumber: ...,
546565
// .systemFileNumber: ...,
547-
// .type: ...,
548566
// .ownerAccountID: ...,
549567
// .groupownerAccountID: ...,
550568
// .ownerAccountName: ...,

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ final class FileManagerTests : XCTestCase {
635635
File("foo", attributes: [.posixPermissions : UInt16(0o644)])
636636
}.test {
637637
let attributes = try $0.attributesOfItem(atPath: "foo")
638+
#if !os(Windows)
638639
// Ensure the unconventional UInt16 was accepted as input
639640
XCTAssertEqual(attributes[.posixPermissions] as? UInt, 0o644)
640641
#if FOUNDATION_FRAMEWORK
@@ -643,6 +644,7 @@ final class FileManagerTests : XCTestCase {
643644
// Ensure that the file type can be converted to a String when it is an ObjC enum
644645
XCTAssertEqual(attributes[.type] as? String, FileAttributeType.typeRegular.rawValue)
645646
#endif
647+
#endif
646648
// Ensure that the file type can be converted to a FileAttributeType when it is an ObjC enum and in swift-foundation
647649
XCTAssertEqual(attributes[.type] as? FileAttributeType, .typeRegular)
648650

0 commit comments

Comments
 (0)