Skip to content

Foundation: add some type conversion extensions for Windows #4747

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Sources/Foundation/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -146,7 +146,8 @@ add_library(Foundation
URLQueryItem.swift
URLResourceKey.swift
UserDefaults.swift
UUID.swift)
UUID.swift
WinSDK+Extensions.swift)
target_compile_definitions(Foundation PRIVATE
DEPLOYMENT_RUNTIME_SWIFT)
target_compile_options(Foundation PUBLIC
2 changes: 1 addition & 1 deletion Sources/Foundation/FileHandle.swift
Original file line number Diff line number Diff line change
@@ -880,7 +880,7 @@ extension FileHandle {
if error == ERROR_ACCESS_DENIED {
var fileInfo = BY_HANDLE_FILE_INFORMATION()
GetFileInformationByHandle(self._handle, &fileInfo)
if fileInfo.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
if fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY {
translatedError = Int32(ERROR_DIRECTORY_NOT_SUPPORTED)
}
}
64 changes: 32 additions & 32 deletions Sources/Foundation/FileManager+Win32.swift
Original file line number Diff line number Diff line change
@@ -228,8 +228,8 @@ extension FileManager {

try _contentsOfDir(atPath: path, { (entryName, entryType) throws in
contents.append(entryName)
if entryType & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
&& entryType & FILE_ATTRIBUTE_REPARSE_POINT != FILE_ATTRIBUTE_REPARSE_POINT {
if DWORD(entryType) & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
&& DWORD(entryType) & FILE_ATTRIBUTE_REPARSE_POINT != FILE_ATTRIBUTE_REPARSE_POINT {
let subPath: String = joinPath(prefix: path, suffix: entryName)
let entries = try subpathsOfDirectory(atPath: subPath)
contents.append(contentsOf: entries.map { joinPath(prefix: entryName, suffix: $0).standardizingPath })
@@ -313,7 +313,7 @@ extension FileManager {
guard let faAttributes = try? windowsFileAttributes(atPath: resolvedDest) else {
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path, destPath])
}
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY {
dwFlags |= DWORD(SYMBOLIC_LINK_FLAG_DIRECTORY)
}
}
@@ -327,7 +327,7 @@ extension FileManager {

internal func _destinationOfSymbolicLink(atPath path: String) throws -> String {
let faAttributes = try windowsFileAttributes(atPath: path)
guard faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) else {
guard faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT else {
throw _NSErrorWithWindowsError(DWORD(ERROR_BAD_ARGUMENTS), reading: false)
}

@@ -484,12 +484,12 @@ extension FileManager {

internal func _copySymlink(atPath srcPath: String, toPath dstPath: String, variant: String = "Copy") throws {
let faAttributes: WIN32_FILE_ATTRIBUTE_DATA = try windowsFileAttributes(atPath: srcPath)
guard faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) else {
guard faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT else {
throw _NSErrorWithErrno(EINVAL, reading: true, path: srcPath, extraUserInfo: extraErrorInfo(srcPath: srcPath, dstPath: dstPath, userVariant: variant))
}

let destination = try destinationOfSymbolicLink(atPath: srcPath)
let isDir = try windowsFileAttributes(atPath: srcPath).dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY)
let isDir = try windowsFileAttributes(atPath: srcPath).dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
if fileExists(atPath: dstPath) {
try removeItem(atPath: dstPath)
}
@@ -585,15 +585,15 @@ extension FileManager {
}
}

if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY {
if try !FileManager.default._fileSystemRepresentation(withPath: path, {
SetFileAttributesW($0, faAttributes.dwFileAttributes & ~DWORD(FILE_ATTRIBUTE_READONLY))
SetFileAttributesW($0, faAttributes.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
}) {
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
}
}

if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == 0 {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == 0 {
if try !FileManager.default._fileSystemRepresentation(withPath: path, DeleteFileW) {
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
}
@@ -635,15 +635,15 @@ extension FileManager {
}

itemPath = "\(currentDir)\\\(file)"
if ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
if ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY {
if try !FileManager.default._fileSystemRepresentation(withPath: itemPath, {
SetFileAttributesW($0, ffd.dwFileAttributes & ~DWORD(FILE_ATTRIBUTE_READONLY))
SetFileAttributesW($0, ffd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY)
}) {
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
}
}

if (ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0) {
if file != "." && file != ".." {
dirStack.append(itemPath)
}
@@ -682,7 +682,7 @@ extension FileManager {
internal func _fileExists(atPath path: String, isDirectory: UnsafeMutablePointer<ObjCBool>?) -> Bool {
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = WIN32_FILE_ATTRIBUTE_DATA()
do { faAttributes = try windowsFileAttributes(atPath: path) } catch { return false }
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT {
let handle: HANDLE = (try? FileManager.default._fileSystemRepresentation(withPath: path) {
CreateFileW($0, /* dwDesiredAccess= */ DWORD(0),
DWORD(FILE_SHARE_READ), /* lpSecurityAttributes= */ nil,
@@ -695,11 +695,11 @@ extension FileManager {
if let isDirectory = isDirectory {
var info: BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION()
GetFileInformationByHandle(handle, &info)
isDirectory.pointee = ObjCBool(info.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY))
isDirectory.pointee = ObjCBool(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
}
} else {
if let isDirectory = isDirectory {
isDirectory.pointee = ObjCBool(faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY))
isDirectory.pointee = ObjCBool(faAttributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY)
}
}
return true
@@ -713,7 +713,7 @@ extension FileManager {

internal func _isWritableFile(atPath path: String) -> Bool {
guard let faAttributes: WIN32_FILE_ATTRIBUTE_DATA = try? windowsFileAttributes(atPath: path) else { return false }
return faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) != DWORD(FILE_ATTRIBUTE_READONLY)
return faAttributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY != FILE_ATTRIBUTE_READONLY
}

internal func _isExecutableFile(atPath path: String) -> Bool {
@@ -730,12 +730,12 @@ extension FileManager {
let parent = path._nsObject.deletingLastPathComponent
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = WIN32_FILE_ATTRIBUTE_DATA()
do { faAttributes = try windowsFileAttributes(atPath: parent) } catch { return false }
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == DWORD(FILE_ATTRIBUTE_READONLY) {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY {
return false
}

do { faAttributes = try windowsFileAttributes(atPath: path) } catch { return false }
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == DWORD(FILE_ATTRIBUTE_READONLY) {
if faAttributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY {
return false
}

@@ -785,15 +785,15 @@ extension FileManager {
statInfo.st_ino = 0
statInfo.st_rdev = _dev_t(info.dwVolumeSerialNumber)

let isReparsePoint = info.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) != 0
let isDir = info.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) != 0
let isReparsePoint = info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0
let isDir = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0
let fileMode = isDir ? _S_IFDIR : _S_IFREG
// On a symlink to a directory, Windows sets both the REPARSE_POINT and
// DIRECTORY attributes. Since Windows doesn't provide S_IFLNK and we
// want unix style "symlinks to directories are not directories
// themselves, we say symlinks are regular files
statInfo.st_mode = UInt16(isReparsePoint ? _S_IFREG : fileMode)
let isReadOnly = info.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) != 0
let isReadOnly = info.dwFileAttributes & FILE_ATTRIBUTE_READONLY != 0
statInfo.st_mode |= UInt16(isReadOnly ? _S_IREAD : (_S_IREAD | _S_IWRITE))
statInfo.st_mode |= UInt16(_S_IEXEC)

@@ -860,21 +860,21 @@ extension FileManager {

let path1Attrs = path1FileInfo.dwFileAttributes
let path2Attrs = path2FileInfo.dwFileAttributes
if path1Attrs & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
|| path2Attrs & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT {
guard path1Attrs & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
&& path2Attrs & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT else {
if path1Attrs & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT
|| path2Attrs & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT {
guard path1Attrs & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT
&& path2Attrs & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT else {
return false
}
guard let pathDest1 = try? _destinationOfSymbolicLink(atPath: path1),
let pathDest2 = try? _destinationOfSymbolicLink(atPath: path2) else {
return false
}
return pathDest1 == pathDest2
} else if DWORD(FILE_ATTRIBUTE_DIRECTORY) & path1Attrs == DWORD(FILE_ATTRIBUTE_DIRECTORY)
|| DWORD(FILE_ATTRIBUTE_DIRECTORY) & path2Attrs == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
guard DWORD(FILE_ATTRIBUTE_DIRECTORY) & path1Attrs == DWORD(FILE_ATTRIBUTE_DIRECTORY)
&& DWORD(FILE_ATTRIBUTE_DIRECTORY) & path2Attrs == FILE_ATTRIBUTE_DIRECTORY else {
} else if FILE_ATTRIBUTE_DIRECTORY & path1Attrs == FILE_ATTRIBUTE_DIRECTORY
|| FILE_ATTRIBUTE_DIRECTORY & path2Attrs == FILE_ATTRIBUTE_DIRECTORY {
guard FILE_ATTRIBUTE_DIRECTORY & path1Attrs == FILE_ATTRIBUTE_DIRECTORY
&& FILE_ATTRIBUTE_DIRECTORY & path2Attrs == FILE_ATTRIBUTE_DIRECTORY else {
return false
}
return _compareDirectories(atPath: path1, andPath: path2)
@@ -966,8 +966,8 @@ extension FileManager {
return firstValidItem()
}

let isDir = attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) &&
attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == 0
let isDir = attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY &&
attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == 0
if isDir && (level == 0 || !_options.contains(.skipsSubdirectoryDescendants)) {
var ffd = WIN32_FIND_DATAW()
let capacity = MemoryLayout.size(ofValue: ffd.cFileName)
@@ -986,7 +986,7 @@ extension FileManager {
}
if file == "." || file == ".." { continue }
if _options.contains(.skipsHiddenFiles) &&
ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_HIDDEN) == DWORD(FILE_ATTRIBUTE_HIDDEN) {
ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN == FILE_ATTRIBUTE_HIDDEN {
continue
}
_stack.append(URL(fileURLWithPath: file, relativeTo: _lastReturned))
12 changes: 6 additions & 6 deletions Sources/Foundation/FileManager.swift
Original file line number Diff line number Diff line change
@@ -431,8 +431,8 @@ open class FileManager : NSObject {
}

let hiddenAttrs = isHidden
? attrs | DWORD(FILE_ATTRIBUTE_HIDDEN)
: attrs & ~DWORD(FILE_ATTRIBUTE_HIDDEN)
? attrs | FILE_ATTRIBUTE_HIDDEN
: attrs & ~FILE_ATTRIBUTE_HIDDEN
guard SetFileAttributesW(fsRep, hiddenAttrs) else {
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
}
@@ -604,7 +604,7 @@ open class FileManager : NSObject {

#if os(Windows)
let attrs = attributes.dwFileAttributes
result[._hidden] = attrs & DWORD(FILE_ATTRIBUTE_HIDDEN) != 0
result[._hidden] = attrs & FILE_ATTRIBUTE_HIDDEN != 0
#endif
result[.ownerAccountID] = NSNumber(value: UInt64(s.st_uid))
result[.groupOwnerAccountID] = NSNumber(value: UInt64(s.st_gid))
@@ -1295,9 +1295,9 @@ public struct FileAttributeType : RawRepresentable, Equatable, Hashable {

#if os(Windows)
internal init(attributes: WIN32_FILE_ATTRIBUTE_DATA, atPath path: String) {
if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DEVICE) == DWORD(FILE_ATTRIBUTE_DEVICE) {
if attributes.dwFileAttributes & FILE_ATTRIBUTE_DEVICE == FILE_ATTRIBUTE_DEVICE {
self = .typeCharacterSpecial
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) {
} else if attributes.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == FILE_ATTRIBUTE_REPARSE_POINT {
// A reparse point may or may not actually be a symbolic link, we need to read the reparse tag
let handle: HANDLE = (try? FileManager.default._fileSystemRepresentation(withPath: path) {
CreateFileW($0, /*dwDesiredAccess=*/DWORD(0),
@@ -1318,7 +1318,7 @@ public struct FileAttributeType : RawRepresentable, Equatable, Hashable {
return
}
self = tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK ? .typeSymbolicLink : .typeRegular
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
} else if attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY {
// Note: Since Windows marks directory symlinks as both
// directories and reparse points, having this after the
// reparse point check implicitly encodes Windows
2 changes: 1 addition & 1 deletion Sources/Foundation/NSPathUtilities.swift
Original file line number Diff line number Diff line change
@@ -767,7 +767,7 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin
DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
nil,
DWORD(OPEN_EXISTING),
DWORD(FILE_ATTRIBUTE_NORMAL),
FILE_ATTRIBUTE_NORMAL,
nil),
h != INVALID_HANDLE_VALUE else {
throw _NSErrorWithWindowsError(GetLastError(), reading: false)
35 changes: 35 additions & 0 deletions Sources/Foundation/WinSDK+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

#if os(Windows)
import WinSDK

internal var FILE_ATTRIBUTE_DEVICE: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_DEVICE)
}

internal var FILE_ATTRIBUTE_DIRECTORY: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_DIRECTORY)
}

internal var FILE_ATTRIBUTE_NORMAL: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_NORMAL)
}

internal var FILE_ATTRIBUTE_HIDDEN: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_HIDDEN)
}

internal var FILE_ATTRIBUTE_READONLY: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_READONLY)
}

internal var FILE_ATTRIBUTE_REPARSE_POINT: DWORD {
DWORD(WinSDK.FILE_ATTRIBUTE_REPARSE_POINT)
}
#endif