From 0ea3e4d7dce6bf4f56ec2ff1e616c70493655f83 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Fri, 15 Mar 2019 16:59:27 -0700 Subject: [PATCH] Windows: Implement attributesOfItem with _lstat --- Foundation/FileManager.swift | 42 ++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/Foundation/FileManager.swift b/Foundation/FileManager.swift index 727a2cdf9f..2dfcdec0b2 100644 --- a/Foundation/FileManager.swift +++ b/Foundation/FileManager.swift @@ -871,14 +871,6 @@ open class FileManager : NSObject { open func attributesOfItem(atPath path: String) throws -> [FileAttributeKey : Any] { var result: [FileAttributeKey:Any] = [:] -#if os(Windows) - let faAttributes: WIN32_FILE_ATTRIBUTE_DATA = try windowsFileAttributes(atPath: path) - - result[.size] = NSNumber(value: (faAttributes.nFileSizeHigh << 32) | faAttributes.nFileSizeLow) - result[.modificationDate] = Date(timeIntervalSinceReferenceDate: TimeInterval(faAttributes.ftLastWriteTime)) - // FIXME(compnerd) what about .posixPermissions, .referenceCount, .systemNumber, .systemFileNumber, .ownerAccountName, .groupOwnerAccountName, .type, .immuatable, .appendOnly, .ownerAccountID, .groupOwnerAccountID -#else - #if os(Linux) let (s, creationDate) = try _statxFile(atPath: path) result[.creationDate] = creationDate @@ -892,29 +884,36 @@ open class FileManager : NSObject { let ti = (TimeInterval(s.st_mtimespec.tv_sec) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtimespec.tv_nsec)) #elseif os(Android) let ti = (TimeInterval(s.st_mtime) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtime_nsec)) +#elseif os(Windows) + let ti = (TimeInterval(s.st_mtime) - kCFAbsoluteTimeIntervalSince1970) #else let ti = (TimeInterval(s.st_mtim.tv_sec) - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * TimeInterval(s.st_mtim.tv_nsec)) #endif result[.modificationDate] = Date(timeIntervalSinceReferenceDate: ti) - - result[.posixPermissions] = NSNumber(value: UInt64(s.st_mode & ~S_IFMT)) + + result[.posixPermissions] = NSNumber(value: _filePermissionsMask(mode: UInt32(s.st_mode))) result[.referenceCount] = NSNumber(value: UInt64(s.st_nlink)) result[.systemNumber] = NSNumber(value: UInt64(s.st_dev)) result[.systemFileNumber] = NSNumber(value: UInt64(s.st_ino)) - + +#if os(Windows) + result[.deviceIdentifier] = NSNumber(value: UInt64(s.st_rdev)) + let type = FileAttributeType(attributes: try windowsFileAttributes(atPath: path)) +#else if let pwd = getpwuid(s.st_uid), pwd.pointee.pw_name != nil { let name = String(cString: pwd.pointee.pw_name) result[.ownerAccountName] = name } - + if let grd = getgrgid(s.st_gid), grd.pointee.gr_name != nil { let name = String(cString: grd.pointee.gr_name) result[.groupOwnerAccountName] = name } let type = FileAttributeType(statMode: s.st_mode) +#endif result[.type] = type - + if type == .typeBlockSpecial || type == .typeCharacterSpecial { result[.deviceIdentifier] = NSNumber(value: UInt64(s.st_rdev)) } @@ -929,11 +928,10 @@ open class FileManager : NSObject { #endif result[.ownerAccountID] = NSNumber(value: UInt64(s.st_uid)) result[.groupOwnerAccountID] = NSNumber(value: UInt64(s.st_gid)) -#endif return result } - + /* attributesOfFileSystemForPath:error: returns an NSDictionary of key/value pairs containing the attributes of the filesystem containing the provided path. If this method returns 'nil', an NSError will be returned by reference in the 'error' parameter. This method does not traverse a terminal symlink. This method replaces fileSystemAttributesAtPath:. @@ -1870,15 +1868,21 @@ open class FileManager : NSObject { return statInfo } - internal func _permissionsOfItem(atPath path: String) throws -> Int { - let fileInfo = try _lstatFile(atPath: path) + internal func _filePermissionsMask(mode : UInt32) -> Int { #if os(Windows) - return Int(fileInfo.st_mode & ~UInt16(ucrt.S_IFMT)) + return Int(mode & ~UInt32(ucrt.S_IFMT)) +#elseif canImport(Darwin) + return Int(mode & ~UInt32(S_IFMT)) #else - return Int(fileInfo.st_mode & ~S_IFMT) + return Int(mode & ~S_IFMT) #endif } + internal func _permissionsOfItem(atPath path: String) throws -> Int { + let fileInfo = try _lstatFile(atPath: path) + return _filePermissionsMask(mode: UInt32(fileInfo.st_mode)) + } + #if os(Linux) // statx() is only supported by Linux kernels >= 4.11.0