@@ -553,48 +553,64 @@ extension _FileManagerImpl {
553553 func attributesOfItem( atPath path: String ) throws -> [ FileAttributeKey : Any ] {
554554#if os(Windows)
555555 return try path. withNTPathRepresentation { pwszPath in
556- var faAttributes : WIN32_FILE_ATTRIBUTE_DATA = . init( )
557- guard GetFileAttributesExW ( pwszPath, GetFileExInfoStandard, & faAttributes) else {
558- throw CocoaError . errorWithFilePath ( path, win32: GetLastError ( ) , reading: true )
559- }
560-
561556 let hFile = CreateFileW ( pwszPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nil , OPEN_EXISTING, 0 , nil )
562557 if hFile == INVALID_HANDLE_VALUE {
563558 throw CocoaError . errorWithFilePath ( path, win32: GetLastError ( ) , reading: true )
564559 }
565560 defer { CloseHandle ( hFile) }
566561
562+ var info : BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION ( )
563+ guard GetFileInformationByHandle ( hFile, & info) else {
564+ throw CocoaError . errorWithFilePath ( path, win32: GetLastError ( ) , reading: true )
565+ }
566+
567567 let dwFileType = GetFileType ( hFile)
568568 let fatType : FileAttributeType = switch ( dwFileType) {
569569 case FILE_TYPE_CHAR: FileAttributeType . typeCharacterSpecial
570570 case FILE_TYPE_DISK:
571- faAttributes . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
571+ info . dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
572572 ? FileAttributeType . typeDirectory
573573 : FileAttributeType . typeRegular
574574 case FILE_TYPE_PIPE: FileAttributeType . typeSocket
575575 case FILE_TYPE_UNKNOWN: FileAttributeType . typeUnknown
576576 default : FileAttributeType . typeUnknown
577577 }
578578
579- let size : UInt64 = ( UInt64 ( faAttributes. nFileSizeHigh) << 32 ) | UInt64 ( faAttributes. nFileSizeLow)
580- let creation : Date = Date ( timeIntervalSince1970: faAttributes. ftCreationTime. timeIntervalSince1970)
581- let modification : Date = Date ( timeIntervalSince1970: faAttributes. ftLastWriteTime. timeIntervalSince1970)
579+ let systemNumber = UInt64 ( info. dwVolumeSerialNumber)
580+ let systemFileNumber = UInt64 ( info. nFileIndexHigh << 32 ) | UInt64 ( info. nFileIndexLow)
581+ let referenceCount = UInt64 ( info. nNumberOfLinks)
582+
583+ let isReadOnly = info. dwFileAttributes & FILE_ATTRIBUTE_READONLY != 0
584+ // Directories are always considered executable, but we check for other types
585+ let isExecutable = fatType == . typeDirectory || SaferiIsExecutableFileType ( pwszPath, 0 )
586+ var posixPermissions = UInt16 ( _S_IREAD)
587+ if !isReadOnly {
588+ posixPermissions |= UInt16 ( _S_IWRITE)
589+ }
590+ if isExecutable {
591+ posixPermissions |= UInt16 ( _S_IEXEC)
592+ }
593+
594+ let size : UInt64 = ( UInt64 ( info. nFileSizeHigh) << 32 ) | UInt64 ( info. nFileSizeLow)
595+ let creation : Date = Date ( timeIntervalSince1970: info. ftCreationTime. timeIntervalSince1970)
596+ let modification : Date = Date ( timeIntervalSince1970: info. ftLastWriteTime. timeIntervalSince1970)
582597 return [
583598 . size: _writeFileAttributePrimitive ( size, as: UInt . self) ,
584599 . modificationDate: modification,
585600 . creationDate: creation,
586601 . type: fatType,
602+ . systemNumber: _writeFileAttributePrimitive ( systemNumber, as: UInt . self) ,
603+ . systemFileNumber: _writeFileAttributePrimitive ( systemFileNumber, as: UInt . self) ,
604+ . posixPermissions: _writeFileAttributePrimitive ( posixPermissions, as: UInt . self) ,
605+ . referenceCount: _writeFileAttributePrimitive ( referenceCount, as: UInt . self) ,
606+
607+ // Uid is always 0 on Windows systems
608+ . ownerAccountID: _writeFileAttributePrimitive ( 0 , as: UInt . self) ,
609+
610+ // Group id is always 0 on Windows
611+ . groupOwnerAccountID: _writeFileAttributePrimitive ( 0 , as: UInt . self)
587612
588- // TODO(compnerd) support these attributes, remapping the Windows semantics...
589- // .posixPermissions: ...,
590- // .referenceCount: ...,
591- // .systemNumber: ...,
592- // .systemFileNumber: ...,
593- // .ownerAccountID: ...,
594- // .groupownerAccountID: ...,
595- // .ownerAccountName: ...,
596- // .groupOwnerAccountName: ...,
597- // .deviceIdentifier: ...,
613+ // TODO: Support .deviceIdentifier
598614 ]
599615 }
600616#else
0 commit comments