Skip to content

Commit 973afe6

Browse files
authored
Merge pull request swiftlang#2659 from compnerd/the-win-path
Foundation: continue Windows file system cleanup
2 parents c326918 + 34b20d9 commit 973afe6

File tree

5 files changed

+93
-74
lines changed

5 files changed

+93
-74
lines changed

Diff for: CoreFoundation/Base.subproj/CFPlatform.c

+6
Original file line numberDiff line numberDiff line change
@@ -1527,9 +1527,15 @@ CF_EXPORT char **_CFEnviron(void) {
15271527
#endif
15281528
}
15291529

1530+
#if TARGET_OS_WIN32
1531+
CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const unsigned short *path, int opts, mode_t mode) {
1532+
return _wopen(path, opts, mode);
1533+
}
1534+
#else
15301535
CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const char *path, int opts, mode_t mode) {
15311536
return open(path, opts, mode);
15321537
}
1538+
#endif
15331539

15341540
int _CFOpenFile(const char *path, int opts) {
15351541
return open(path, opts, 0);

Diff for: CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h

+4
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,11 @@ CF_CROSS_PLATFORM_EXPORT CFIndex __CFCharDigitValue(UniChar ch);
480480

481481
#pragma mark - File Functions
482482

483+
#if TARGET_OS_WIN32
484+
CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const unsigned short *path, int opts, mode_t mode);
485+
#else
483486
CF_CROSS_PLATFORM_EXPORT int _CFOpenFileWithMode(const char *path, int opts, mode_t mode);
487+
#endif
484488
CF_CROSS_PLATFORM_EXPORT void *_CFReallocf(void *ptr, size_t size);
485489
CF_CROSS_PLATFORM_EXPORT int _CFOpenFile(const char *path, int opts);
486490

Diff for: Foundation/FileHandle.swift

+5-10
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,10 @@ open class FileHandle : NSObject {
431431
}
432432

433433
internal convenience init?(path: String, flags: Int32, createMode: Int) {
434-
let fd = _CFOpenFileWithMode(path, flags, mode_t(createMode))
435-
guard fd > 0 else { return nil }
434+
guard let fd: Int32 = try? FileManager.default._fileSystemRepresentation(withPath: path, {
435+
_CFOpenFileWithMode($0, flags, mode_t(createMode))
436+
}), fd > 0 else { return nil }
437+
436438
self.init(fileDescriptor: fd, closeOnDealloc: true)
437439
if _handle == INVALID_HANDLE_VALUE { return nil }
438440
}
@@ -456,15 +458,8 @@ open class FileHandle : NSObject {
456458
}
457459
#endif
458460

459-
internal convenience init?(fileSystemRepresentation: UnsafePointer<Int8>, flags: Int32, createMode: Int) {
460-
#if os(Windows)
461-
var fd: Int32 = -1
462-
if let path = String(cString: fileSystemRepresentation).cString(using: .utf16) {
463-
fd = _CFOpenFileWithMode(path, flags, mode_t(createMode))
464-
}
465-
#else
461+
internal convenience init?(fileSystemRepresentation: UnsafePointer<NativeFSRCharType>, flags: Int32, createMode: Int) {
466462
let fd = _CFOpenFileWithMode(fileSystemRepresentation, flags, mode_t(createMode))
467-
#endif
468463
guard fd > 0 else { return nil }
469464
self.init(fileDescriptor: fd, closeOnDealloc: true)
470465
}

Diff for: Foundation/FileManager+Win32.swift

+77-63
Original file line numberDiff line numberDiff line change
@@ -583,21 +583,24 @@ extension FileManager {
583583
}
584584
dirStack.append(itemPath)
585585
var ffd: WIN32_FIND_DATAW = WIN32_FIND_DATAW()
586-
let h: HANDLE = (itemPath + "\\*").withCString(encodedAs: UTF16.self, {
587-
FindFirstFileW($0, &ffd)
588-
})
589-
guard h != INVALID_HANDLE_VALUE else {
590-
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [itemPath])
586+
let capacity = MemoryLayout.size(ofValue: ffd.cFileName)
587+
588+
let handle: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: joinPath(prefix: itemPath, suffix: "*")) {
589+
FindFirstFileW($0, &ffd)
591590
}
592-
defer { FindClose(h) }
591+
if handle == INVALID_HANDLE_VALUE {
592+
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [itemPath])
593+
}
594+
defer { FindClose(handle) }
593595

594596
repeat {
595-
let fileArr = Array<WCHAR>(
596-
UnsafeBufferPointer(start: &ffd.cFileName.0,
597-
count: MemoryLayout.size(ofValue: ffd.cFileName)))
598-
let file = String(decodingCString: fileArr, as: UTF16.self)
599-
itemPath = "\(currentDir)\\\(file)"
597+
let file = withUnsafePointer(to: &ffd.cFileName) {
598+
$0.withMemoryRebound(to: WCHAR.self, capacity: capacity) {
599+
String(decodingCString: $0, as: UTF16.self)
600+
}
601+
}
600602

603+
itemPath = "\(currentDir)\\\(file)"
601604
if ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
602605
let readableAttributes = ffd.dwFileAttributes & DWORD(bitPattern: ~FILE_ATTRIBUTE_READONLY)
603606
guard itemPath.withCString(encodedAs: UTF16.self, { SetFileAttributesW($0, readableAttributes) }) else {
@@ -617,7 +620,7 @@ extension FileManager {
617620
throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file])
618621
}
619622
}
620-
} while FindNextFileW(h, &ffd)
623+
} while FindNextFileW(handle, &ffd)
621624
} catch {
622625
if !shouldProceedAfterError(error, removingItemAtPath: itemPath, isURL: isURL) {
623626
throw error
@@ -646,18 +649,24 @@ extension FileManager {
646649
var faAttributes: WIN32_FILE_ATTRIBUTE_DATA = WIN32_FILE_ATTRIBUTE_DATA()
647650
do { faAttributes = try windowsFileAttributes(atPath: path) } catch { return false }
648651
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) {
649-
do {
650-
let contents = try destinationOfSymbolicLink(atPath: path)
651-
let resolvedPath = contents.isAbsolutePath
652-
? contents
653-
: joinPath(prefix: path.deletingLastPathComponent, suffix: contents)
654-
try faAttributes = windowsFileAttributes(atPath: resolvedPath)
655-
} catch {
656-
return false
657-
}
658-
}
659-
if let isDirectory = isDirectory {
652+
guard let handle: HANDLE = try? FileManager.default._fileSystemRepresentation(withPath: path, {
653+
CreateFileW($0, /* dwDesiredAccess= */ DWORD(0),
654+
DWORD(FILE_SHARE_READ), /* lpSecurityAttributes= */ nil,
655+
DWORD(OPEN_EXISTING),
656+
DWORD(FILE_FLAG_BACKUP_SEMANTICS), /* hTemplateFile= */ nil)
657+
}) else { return false }
658+
if handle == INVALID_HANDLE_VALUE { return false }
659+
defer { CloseHandle(handle) }
660+
661+
if let isDirectory = isDirectory {
662+
var info: BY_HANDLE_FILE_INFORMATION = BY_HANDLE_FILE_INFORMATION()
663+
GetFileInformationByHandle(handle, &info)
664+
isDirectory.pointee = ObjCBool(info.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY))
665+
}
666+
} else {
667+
if let isDirectory = isDirectory {
660668
isDirectory.pointee = ObjCBool(faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY))
669+
}
661670
}
662671
return true
663672
}
@@ -758,21 +767,24 @@ extension FileManager {
758767
}
759768

760769
internal func _contentsEqual(atPath path1: String, andPath path2: String) -> Bool {
761-
guard let path1Handle = path1.withCString(encodedAs: UTF16.self, {
762-
CreateFileW($0, GENERIC_READ, DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), nil,
763-
DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS), nil)
764-
}), path1Handle != INVALID_HANDLE_VALUE else {
765-
return false
766-
}
767-
770+
guard let path1Handle: HANDLE = try? FileManager.default._fileSystemRepresentation(withPath: path1, {
771+
CreateFileW($0, GENERIC_READ,
772+
DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
773+
nil, DWORD(OPEN_EXISTING),
774+
DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS),
775+
nil)
776+
}) else { return false }
777+
if path1Handle == INVALID_HANDLE_VALUE { return false }
768778
defer { CloseHandle(path1Handle) }
769779

770-
guard let path2Handle = path2.withCString(encodedAs: UTF16.self, {
771-
CreateFileW($0, GENERIC_READ, DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), nil,
772-
DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS), nil)
773-
}), path2Handle != INVALID_HANDLE_VALUE else {
774-
return false
775-
}
780+
guard let path2Handle: HANDLE = try? FileManager.default._fileSystemRepresentation(withPath: path2, {
781+
CreateFileW($0, GENERIC_READ,
782+
DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
783+
nil, DWORD(OPEN_EXISTING),
784+
DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS),
785+
nil)
786+
}) else { return false }
787+
if path2Handle == INVALID_HANDLE_VALUE { return false }
776788
defer { CloseHandle(path2Handle) }
777789

778790
let file1Type = GetFileType(path1Handle)
@@ -829,14 +841,12 @@ extension FileManager {
829841
return true
830842
}
831843

832-
let path1Fsr = fileSystemRepresentation(withPath: path1)
833-
defer { path1Fsr.deallocate() }
834-
let path2Fsr = fileSystemRepresentation(withPath: path2)
835-
defer { path2Fsr.deallocate() }
836-
return _compareFiles(withFileSystemRepresentation: path1Fsr,
837-
andFileSystemRepresentation: path2Fsr,
838-
size: (Int64(path1FileInfo.nFileSizeHigh) << 32) | Int64(path1FileInfo.nFileSizeLow),
839-
bufSize: 0x1000)
844+
return try! FileManager.default._fileSystemRepresentation(withPath: path1, andPath: path2) {
845+
_compareFiles(withFileSystemRepresentation: $0,
846+
andFileSystemRepresentation: $1,
847+
size: (Int64(path1FileInfo.nFileSizeHigh) << 32) | Int64(path1FileInfo.nFileSizeLow),
848+
bufSize: 0x1000)
849+
}
840850
}
841851
}
842852

@@ -891,10 +901,13 @@ extension FileManager {
891901
func firstValidItem() -> URL? {
892902
while let url = _stack.popLast() {
893903
if !FileManager.default.fileExists(atPath: url.path) {
894-
guard let handler = _errorHandler,
895-
handler(url, _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [url.path]))
896-
else { return nil }
897-
continue
904+
if let handler = _errorHandler {
905+
if !handler(url, _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [url.path])) {
906+
return nil
907+
}
908+
} else {
909+
return nil
910+
}
898911
}
899912
_lastReturned = url
900913
return _lastReturned
@@ -910,31 +923,32 @@ extension FileManager {
910923
return firstValidItem()
911924
}
912925

913-
let isDir = attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY)
914-
&& attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == 0
926+
let isDir = attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) &&
927+
attrs.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == 0
915928
if isDir && (level == 0 || !_options.contains(.skipsSubdirectoryDescendants)) {
916929
var ffd = WIN32_FIND_DATAW()
917-
let dirPath = joinPath(prefix: _lastReturned.path, suffix: "*")
918-
let handle = try? FileManager.default._fileSystemRepresentation(withPath: dirPath) {
930+
let capacity = MemoryLayout.size(ofValue: ffd.cFileName)
931+
932+
guard let handle = try? FileManager.default._fileSystemRepresentation(withPath: joinPath(prefix: _lastReturned.path, suffix: "*"), {
919933
FindFirstFileW($0, &ffd)
920-
}
934+
}) else { return firstValidItem() }
921935
if handle == INVALID_HANDLE_VALUE { return firstValidItem() }
922936
defer { FindClose(handle) }
923937

924938
repeat {
925-
let fileArr = Array<WCHAR>(
926-
UnsafeBufferPointer(start: &ffd.cFileName.0,
927-
count: MemoryLayout.size(ofValue: ffd.cFileName)))
928-
let file = String(decodingCString: fileArr, as: UTF16.self)
929-
if file != "." && file != ".."
930-
&& (!_options.contains(.skipsHiddenFiles)
931-
|| (ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_HIDDEN) == 0)) {
932-
let relative = URL(fileURLWithPath: file, relativeTo: _lastReturned)
933-
_stack.append(relative)
939+
let file = withUnsafePointer(to: &ffd.cFileName) {
940+
$0.withMemoryRebound(to: WCHAR.self, capacity: capacity) {
941+
String(decodingCString: $0, as: UTF16.self)
942+
}
934943
}
944+
if file == "." || file == ".." { continue }
945+
if _options.contains(.skipsHiddenFiles) &&
946+
ffd.dwFileAttributes & DWORD(FILE_ATTRIBUTE_HIDDEN) == DWORD(FILE_ATTRIBUTE_HIDDEN) {
947+
continue
948+
}
949+
_stack.append(URL(fileURLWithPath: file, relativeTo: _lastReturned))
935950
} while FindNextFileW(handle, &ffd)
936951
}
937-
938952
return firstValidItem()
939953
}
940954

Diff for: Foundation/FileManager.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ open class FileManager : NSObject {
886886
}()
887887
#endif
888888

889-
internal func _compareFiles(withFileSystemRepresentation file1Rep: UnsafePointer<Int8>, andFileSystemRepresentation file2Rep: UnsafePointer<Int8>, size: Int64, bufSize: Int) -> Bool {
889+
internal func _compareFiles(withFileSystemRepresentation file1Rep: UnsafePointer<NativeFSRCharType>, andFileSystemRepresentation file2Rep: UnsafePointer<NativeFSRCharType>, size: Int64, bufSize: Int) -> Bool {
890890
guard let file1 = FileHandle(fileSystemRepresentation: file1Rep, flags: O_RDONLY, createMode: 0) else { return false }
891891
guard let file2 = FileHandle(fileSystemRepresentation: file2Rep, flags: O_RDONLY, createMode: 0) else { return false }
892892

0 commit comments

Comments
 (0)