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
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sources/Foundation/FileHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down
64 changes: 32 additions & 32 deletions Sources/Foundation/FileManager+Win32.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down Expand Up @@ -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)
}
}
Expand All @@ -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)
}

Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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])
}
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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))
Expand Down
12 changes: 6 additions & 6 deletions Sources/Foundation/FileManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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])
}
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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),
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Sources/Foundation/NSPathUtilities.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
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