From a958d038ee888e961308daed21eed86e5bf8604c Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Fri, 16 Jun 2023 08:55:33 -0700 Subject: [PATCH] Foundation: support long file paths for `FileHandle` on Windows When constructing a `FileHandle` using a path, ensure that we use the NT file path representation on Windows. This allows us to access files that may have greater than `MAX_PATH` length. --- Sources/Foundation/FileHandle.swift | 10 +++++----- Sources/Foundation/FileManager+Win32.swift | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Sources/Foundation/FileHandle.swift b/Sources/Foundation/FileHandle.swift index b729aa5b15..a538a2975e 100644 --- a/Sources/Foundation/FileHandle.swift +++ b/Sources/Foundation/FileHandle.swift @@ -432,12 +432,12 @@ open class FileHandle : NSObject { } internal convenience init?(path: String, flags: Int32, createMode: Int) { - guard let fd: Int32 = try? FileManager.default._fileSystemRepresentation(withPath: path, { - _CFOpenFileWithMode($0, flags, mode_t(createMode)) - }), fd > 0 else { return nil } + guard let fd: CInt = try? withNTPathRepresentation(of: path, { + _CFOpenFileWithMode($0, flags, mode_t(createMode)) + }), fd > 0 else { return nil } - self.init(fileDescriptor: fd, closeOnDealloc: true) - if self._handle == INVALID_HANDLE_VALUE { return nil } + self.init(fileDescriptor: fd, closeOnDealloc: true) + if self._handle == INVALID_HANDLE_VALUE { return nil } } #else public init(fileDescriptor fd: Int32, closeOnDealloc closeopt: Bool) { diff --git a/Sources/Foundation/FileManager+Win32.swift b/Sources/Foundation/FileManager+Win32.swift index 7597d43689..d63bad245d 100644 --- a/Sources/Foundation/FileManager+Win32.swift +++ b/Sources/Foundation/FileManager+Win32.swift @@ -30,7 +30,7 @@ extension URL { } -private func withNTPathRepresentation(of path: String, _ body: (UnsafePointer) throws -> Result) throws -> Result { +internal func withNTPathRepresentation(of path: String, _ body: (UnsafePointer) throws -> Result) throws -> Result { guard !path.isEmpty else { throw CocoaError.error(.fileReadInvalidFileName, userInfo: [NSFilePathErrorKey:path]) } @@ -72,6 +72,9 @@ private func withNTPathRepresentation(of path: String, _ body: (UnsafePo _ = GetFullPathNameW(pwszPath, DWORD($0.count), $0.baseAddress, nil) return String(decodingCString: $0.baseAddress!, as: UTF16.self) } + guard !path.hasPrefix(#"\\"#) else { + return try path.withCString(encodedAs: UTF16.self, body) + } return try #"\\?\\#(path)"#.withCString(encodedAs: UTF16.self, body) } }