@@ -1804,7 +1804,6 @@ open class FileManager : NSObject {
18041804 return path1entries. isEmpty
18051805 }
18061806
1807- #if !os(Windows)
18081807 private func _lstatFile( atPath path: String , withFileSystemRepresentation fsRep: UnsafePointer < Int8 > ? = nil ) throws -> stat {
18091808 let _fsRep : UnsafePointer < Int8 >
18101809 if fsRep == nil {
@@ -1818,19 +1817,64 @@ open class FileManager : NSObject {
18181817 }
18191818
18201819 var statInfo = stat ( )
1820+ #if os(Windows)
1821+ let h = path. withCString ( encodedAs: UTF16 . self) {
1822+ CreateFileW ( /*lpFileName=*/$0,
1823+ /*dwDesiredAccess=*/DWORD ( 0 ) ,
1824+ /*dwShareMode=*/DWORD ( FILE_SHARE_READ) ,
1825+ /*lpSecurityAttributes=*/nil ,
1826+ /*dwCreationDisposition=*/DWORD ( OPEN_EXISTING) ,
1827+ /*dwFlagsAndAttributes=*/DWORD ( FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS) ,
1828+ /*hTemplateFile=*/nil )
1829+ }
1830+ if h == INVALID_HANDLE_VALUE {
1831+ throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: false )
1832+ }
1833+ var info : BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION ( )
1834+ GetFileInformationByHandle ( h, & info)
1835+ // Group id is always 0 on Windows
1836+ statInfo. st_gid = 0
1837+ statInfo. st_atime = info. ftLastAccessTime. time_t
1838+ statInfo. st_ctime = info. ftCreationTime. time_t
1839+ statInfo. st_dev = info. dwVolumeSerialNumber
1840+ // inodes have meaning on FAT/HPFS/NTFS
1841+ statInfo. st_ino = 0
1842+ statInfo. st_rdev = info. dwVolumeSerialNumber
1843+
1844+ let isReparsePoint = info. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) != 0
1845+ let isDir = info. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_DIRECTORY) != 0
1846+ let fileMode = isDir ? _S_IFDIR : _S_IFREG
1847+ // On a symlink to a directory, Windows sets both the REPARSE_POINT and
1848+ // DIRECTORY attributes. Since Windows doesn't provide S_IFLNK and we
1849+ // want unix style "symlinks to directories are not directories
1850+ // themselves, we say symlinks are regular files
1851+ statInfo. st_mode = UInt16 ( isReparsePoint ? _S_IFREG : fileMode)
1852+ let isReadOnly = info. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_READONLY) != 0
1853+ statInfo. st_mode |= UInt16 ( isReadOnly ? _S_IREAD : ( _S_IREAD | _S_IWRITE) )
1854+ statInfo. st_mode |= UInt16 ( _S_IEXEC)
1855+
1856+ statInfo. st_mtime = info. ftLastWriteTime. time_t
1857+ statInfo. st_nlink = Int16 ( info. nNumberOfLinks)
1858+ if info. nFileSizeHigh != 0 {
1859+ throw _NSErrorWithErrno ( EOVERFLOW, reading: true , path: path)
1860+ }
1861+ statInfo. st_size = Int32 ( info. nFileSizeLow)
1862+ // Uid is always 0 on Windows systems
1863+ statInfo. st_uid = 0
1864+ CloseHandle ( h)
1865+ #else
18211866 guard lstat ( _fsRep, & statInfo) == 0 else {
18221867 throw _NSErrorWithErrno ( errno, reading: true , path: path)
18231868 }
1869+ #endif
18241870 return statInfo
18251871 }
1826- #endif
18271872
1828- @available ( Windows, deprecated, message: " Not Yet Implemented " )
18291873 internal func _permissionsOfItem( atPath path: String ) throws -> Int {
1874+ let fileInfo = try _lstatFile ( atPath: path)
18301875#if os(Windows)
1831- NSUnimplemented ( )
1876+ return Int ( fileInfo . st_mode & ~ UInt16 ( ucrt . S_IFMT ) )
18321877#else
1833- let fileInfo = try _lstatFile ( atPath: path)
18341878 return Int ( fileInfo. st_mode & ~ S_IFMT)
18351879#endif
18361880 }
0 commit comments