Skip to content

Commit 5e0b63d

Browse files
authored
Merge pull request #2669 from compnerd/fsr-all-the-things
FileManager: cleanup string abuse in FileManager+Win32
2 parents 7b1d3fe + c8bb24f commit 5e0b63d

File tree

1 file changed

+56
-60
lines changed

1 file changed

+56
-60
lines changed

Foundation/FileManager+Win32.swift

Lines changed: 56 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ import CoreFoundation
1212
#if os(Windows)
1313
internal func joinPath(prefix: String, suffix: String) -> String {
1414
var pszPath: PWSTR?
15-
_ = prefix.withCString(encodedAs: UTF16.self) { prefix in
16-
_ = suffix.withCString(encodedAs: UTF16.self) { suffix in
17-
PathAllocCombine(prefix, suffix, ULONG(PATHCCH_ALLOW_LONG_PATHS.rawValue), &pszPath)
18-
}
15+
16+
guard !prefix.isEmpty else { return suffix }
17+
guard !suffix.isEmpty else { return prefix }
18+
19+
_ = try! FileManager.default._fileSystemRepresentation(withPath: prefix, andPath: suffix) {
20+
PathAllocCombine($0, $1, ULONG(PATHCCH_ALLOW_LONG_PATHS.rawValue), &pszPath)
1921
}
2022

2123
let path: String = String(decodingCString: pszPath!, as: UTF16.self)
@@ -196,7 +198,7 @@ extension FileManager {
196198
guard path != "" else {
197199
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInvalidFileName.rawValue, userInfo: [NSFilePathErrorKey : NSString(path)])
198200
}
199-
try (path + "\\*").withCString(encodedAs: UTF16.self) {
201+
try FileManager.default._fileSystemRepresentation(withPath: path + "\\*") {
200202
var ffd: WIN32_FIND_DATAW = WIN32_FIND_DATAW()
201203

202204
let hDirectory: HANDLE = FindFirstFileW($0, &ffd)
@@ -250,20 +252,19 @@ extension FileManager {
250252
internal func _attributesOfFileSystem(forPath path: String) throws -> [FileAttributeKey : Any] {
251253
var result: [FileAttributeKey:Any] = [:]
252254

253-
try path.withCString(encodedAs: UTF16.self) {
255+
try FileManager.default._fileSystemRepresentation(withPath: path) {
254256
let dwLength: DWORD = GetFullPathNameW($0, 0, nil, nil)
255-
guard dwLength != 0 else {
257+
guard dwLength > 0 else {
256258
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path])
257259
}
258-
var szVolumePath: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(dwLength + 1))
259260

261+
var szVolumePath: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(dwLength + 1))
260262
guard GetVolumePathNameW($0, &szVolumePath, dwLength) else {
261263
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path])
262264
}
263265

264266
var liTotal: ULARGE_INTEGER = ULARGE_INTEGER()
265267
var liFree: ULARGE_INTEGER = ULARGE_INTEGER()
266-
267268
guard GetDiskFreeSpaceExW(&szVolumePath, nil, &liTotal, &liFree) else {
268269
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path])
269270
}
@@ -412,24 +413,26 @@ extension FileManager {
412413
}
413414

414415
internal func _canonicalizedPath(toFileAtPath path: String) throws -> String {
415-
var hFile: HANDLE = INVALID_HANDLE_VALUE
416-
path.withCString(encodedAs: UTF16.self) { link in
416+
let hFile: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: path) {
417417
// BACKUP_SEMANTICS are (confusingly) required in order to receive a
418418
// handle to a directory
419-
hFile = CreateFileW(link, 0, DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
420-
nil, DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS),
421-
nil)
422-
}
423-
guard hFile != INVALID_HANDLE_VALUE else {
424-
return try path.withCString(encodedAs: UTF16.self) {
425-
var dwLength = GetFullPathNameW($0, 0, nil, nil)
426-
var szPath = Array<WCHAR>(repeating: 0, count: Int(dwLength + 1))
427-
dwLength = GetFullPathNameW($0, DWORD(szPath.count), &szPath, nil)
428-
guard dwLength > 0 && dwLength <= szPath.count else {
429-
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path])
430-
}
431-
return String(decodingCString: szPath, as: UTF16.self)
419+
CreateFileW($0, /*dwDesiredAccess=*/DWORD(0),
420+
DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
421+
/*lpSecurityAttributes=*/nil, DWORD(OPEN_EXISTING),
422+
DWORD(FILE_FLAG_BACKUP_SEMANTICS), /*hTemplateFile=*/nil)
423+
}
424+
if hFile == INVALID_HANDLE_VALUE {
425+
return try FileManager.default._fileSystemRepresentation(withPath: path) {
426+
var dwLength = GetFullPathNameW($0, 0, nil, nil)
427+
428+
var szPath = Array<WCHAR>(repeating: 0, count: Int(dwLength + 1))
429+
dwLength = GetFullPathNameW($0, DWORD(szPath.count), &szPath, nil)
430+
guard dwLength > 0 && dwLength <= szPath.count else {
431+
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path])
432432
}
433+
434+
return String(decodingCString: szPath, as: UTF16.self)
435+
}
433436
}
434437
defer { CloseHandle(hFile) }
435438

@@ -441,13 +444,11 @@ extension FileManager {
441444
}
442445

443446
internal func _copyRegularFile(atPath srcPath: String, toPath dstPath: String, variant: String = "Copy") throws {
444-
try srcPath.withCString(encodedAs: UTF16.self) { src in
445-
try dstPath.withCString(encodedAs: UTF16.self) { dst in
446-
if !CopyFileW(src, dst, false) {
447-
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [srcPath, dstPath])
448-
}
449-
}
447+
try FileManager.default._fileSystemRepresentation(withPath: srcPath, andPath: dstPath) {
448+
if !CopyFileW($0, $1, false) {
449+
throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [srcPath, dstPath])
450450
}
451+
}
451452
}
452453

453454
internal func _copySymlink(atPath srcPath: String, toPath dstPath: String, variant: String = "Copy") throws {
@@ -539,19 +540,9 @@ extension FileManager {
539540
return
540541
}
541542

542-
guard path != "" else {
543-
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInvalidFileName.rawValue, userInfo: [NSFilePathErrorKey : NSString(path)])
544-
}
545-
546-
let url = URL(fileURLWithPath: path)
547-
var fsrBuf: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(MAX_PATH))
548-
_CFURLGetWideFileSystemRepresentation(url._cfObject, false, &fsrBuf, Int(MAX_PATH))
549-
let length = wcsnlen_s(&fsrBuf, fsrBuf.count)
550-
let fsrPath = String(utf16CodeUnits: &fsrBuf, count: length)
551-
552543
let faAttributes: WIN32_FILE_ATTRIBUTE_DATA
553544
do {
554-
faAttributes = try windowsFileAttributes(atPath: fsrPath)
545+
faAttributes = try windowsFileAttributes(atPath: path)
555546
} catch {
556547
// removeItem on POSIX throws fileNoSuchFile rather than
557548
// fileReadNoSuchFile that windowsFileAttributes will
@@ -562,29 +553,33 @@ extension FileManager {
562553
throw error
563554
}
564555
}
556+
565557
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
566-
let readableAttributes = faAttributes.dwFileAttributes & DWORD(bitPattern: ~FILE_ATTRIBUTE_READONLY)
567-
guard fsrPath.withCString(encodedAs: UTF16.self, { SetFileAttributesW($0, readableAttributes) }) else {
568-
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
569-
}
558+
if try !FileManager.default._fileSystemRepresentation(withPath: path, {
559+
SetFileAttributesW($0, faAttributes.dwFileAttributes & DWORD(bitPattern: ~FILE_ATTRIBUTE_READONLY))
560+
}) {
561+
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
562+
}
570563
}
571564

572565
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == 0 {
573-
if !fsrPath.withCString(encodedAs: UTF16.self, DeleteFileW) {
574-
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
575-
}
576-
return
566+
if try !FileManager.default._fileSystemRepresentation(withPath: path, DeleteFileW) {
567+
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [path])
568+
}
569+
return
577570
}
578-
var dirStack = [fsrPath]
571+
572+
var dirStack = [path]
579573
var itemPath = ""
580574
while let currentDir = dirStack.popLast() {
581575
do {
582576
itemPath = currentDir
583577
guard alreadyConfirmed || shouldRemoveItemAtPath(itemPath, isURL: isURL) else {
584578
continue
585579
}
586-
guard !itemPath.withCString(encodedAs: UTF16.self, RemoveDirectoryW) else {
587-
continue
580+
581+
if try FileManager.default._fileSystemRepresentation(withPath: itemPath, RemoveDirectoryW) {
582+
continue
588583
}
589584
guard GetLastError() == ERROR_DIR_NOT_EMPTY else {
590585
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [itemPath])
@@ -593,7 +588,7 @@ extension FileManager {
593588
var ffd: WIN32_FIND_DATAW = WIN32_FIND_DATAW()
594589
let capacity = MemoryLayout.size(ofValue: ffd.cFileName)
595590

596-
let handle: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: joinPath(prefix: itemPath, suffix: "*")) {
591+
let handle: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: itemPath + "\\*") {
597592
FindFirstFileW($0, &ffd)
598593
}
599594
if handle == INVALID_HANDLE_VALUE {
@@ -610,10 +605,11 @@ extension FileManager {
610605

611606
itemPath = "\(currentDir)\\\(file)"
612607
if ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
613-
let readableAttributes = ffd.dwFileAttributes & DWORD(bitPattern: ~FILE_ATTRIBUTE_READONLY)
614-
guard itemPath.withCString(encodedAs: UTF16.self, { SetFileAttributesW($0, readableAttributes) }) else {
615-
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
616-
}
608+
if try !FileManager.default._fileSystemRepresentation(withPath: itemPath, {
609+
SetFileAttributesW($0, ffd.dwFileAttributes & DWORD(bitPattern: ~FILE_ATTRIBUTE_READONLY))
610+
}) {
611+
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
612+
}
617613
}
618614

619615
if (ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) != 0) {
@@ -624,8 +620,8 @@ extension FileManager {
624620
guard alreadyConfirmed || shouldRemoveItemAtPath(itemPath, isURL: isURL) else {
625621
continue
626622
}
627-
if !itemPath.withCString(encodedAs: UTF16.self, DeleteFileW) {
628-
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
623+
if try !FileManager.default._fileSystemRepresentation(withPath: itemPath, DeleteFileW) {
624+
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
629625
}
630626
}
631627
} while FindNextFileW(handle, &ffd)
@@ -936,7 +932,7 @@ extension FileManager {
936932
var ffd = WIN32_FIND_DATAW()
937933
let capacity = MemoryLayout.size(ofValue: ffd.cFileName)
938934

939-
let handle = (try? FileManager.default._fileSystemRepresentation(withPath: joinPath(prefix: _lastReturned.path, suffix: "*")) {
935+
let handle = (try? FileManager.default._fileSystemRepresentation(withPath: _lastReturned.path + "\\*") {
940936
FindFirstFileW($0, &ffd)
941937
}) ?? INVALID_HANDLE_VALUE
942938
if handle == INVALID_HANDLE_VALUE { return firstValidItem() }

0 commit comments

Comments
 (0)