|
13 | 13 | import let WinSDK.INVALID_FILE_ATTRIBUTES
|
14 | 14 | import WinSDK
|
15 | 15 |
|
| 16 | +private func walk(directory path: URL, _ body: (String, DWORD) throws -> Void) rethrows { |
| 17 | + try path.withUnsafeFileSystemRepresentation { |
| 18 | + try "\\\\?\\\(String(cString: $0!))\\*".withCString(encodedAs: UTF16.self) { |
| 19 | + var ffd: WIN32_FIND_DATAW = .init() |
| 20 | + let capacity = MemoryLayout.size(ofValue: ffd.cFileName) / MemoryLayout<WCHAR>.size |
| 21 | + |
| 22 | + let hFind: HANDLE = FindFirstFileW($0, &ffd) |
| 23 | + if hFind == INVALID_HANDLE_VALUE { |
| 24 | + throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path.path]) |
| 25 | + } |
| 26 | + |
| 27 | + defer { FindClose(hFind) } |
| 28 | + |
| 29 | + repeat { |
| 30 | + let entry: String = withUnsafePointer(to: ffd.cFileName) { |
| 31 | + $0.withMemoryRebound(to: WCHAR.self, capacity: capacity) { |
| 32 | + String(decodingCString: $0, as: UTF16.self) |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + try body(entry, ffd.dwFileAttributes) |
| 37 | + } while FindNextWileW(hFind, &ffd) |
| 38 | + } |
| 39 | + } |
| 40 | +} |
| 41 | + |
16 | 42 | internal func joinPath(prefix: String, suffix: String) -> String {
|
17 | 43 | var pszPath: PWSTR?
|
18 | 44 |
|
@@ -197,29 +223,14 @@ extension FileManager {
|
197 | 223 | }
|
198 | 224 | }
|
199 | 225 |
|
200 |
| - internal func _contentsOfDir(atPath path: String, _ closure: (String, Int32) throws -> () ) throws { |
201 |
| - guard path != "" else { |
202 |
| - throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInvalidFileName.rawValue, userInfo: [NSFilePathErrorKey : NSString(path)]) |
| 226 | + internal func _contentsOfDir(atPath path: String, _ closure: (String, Int32) throws -> Void) throws { |
| 227 | + guard !path.isEmpty else { |
| 228 | + throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.fileReadInvalidFileName.rawValue, userInfo: [NSFilePathErrorKey:NSString(path)]) |
203 | 229 | }
|
204 |
| - try FileManager.default._fileSystemRepresentation(withPath: path + "\\*") { |
205 |
| - var ffd: WIN32_FIND_DATAW = WIN32_FIND_DATAW() |
206 |
| - |
207 |
| - let hDirectory: HANDLE = FindFirstFileW($0, &ffd) |
208 |
| - if hDirectory == INVALID_HANDLE_VALUE { |
209 |
| - throw _NSErrorWithWindowsError(GetLastError(), reading: true, paths: [path]) |
210 |
| - } |
211 |
| - defer { FindClose(hDirectory) } |
212 | 230 |
|
213 |
| - repeat { |
214 |
| - let path: String = withUnsafePointer(to: &ffd.cFileName) { |
215 |
| - $0.withMemoryRebound(to: UInt16.self, capacity: MemoryLayout.size(ofValue: $0) / MemoryLayout<WCHAR>.size) { |
216 |
| - String(decodingCString: $0, as: UTF16.self) |
217 |
| - } |
218 |
| - } |
219 |
| - if path != "." && path != ".." { |
220 |
| - try closure(path.standardizingPath, Int32(ffd.dwFileAttributes)) |
221 |
| - } |
222 |
| - } while FindNextFileW(hDirectory, &ffd) |
| 231 | + try walk(directory: URL(fileURLWithPath: path, isDirectory: true)) { (entry, attributes) in |
| 232 | + if entry == "." || entry == ".." { return } |
| 233 | + try closure(entry.standardizingPath, Int32(attributes)) |
223 | 234 | }
|
224 | 235 | }
|
225 | 236 |
|
@@ -616,46 +627,34 @@ extension FileManager {
|
616 | 627 | throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [itemPath])
|
617 | 628 | }
|
618 | 629 | dirStack.append(itemPath)
|
619 |
| - var ffd: WIN32_FIND_DATAW = WIN32_FIND_DATAW() |
620 |
| - let capacity = MemoryLayout.size(ofValue: ffd.cFileName) |
621 | 630 |
|
622 |
| - let handle: HANDLE = try FileManager.default._fileSystemRepresentation(withPath: itemPath + "\\*") { |
623 |
| - FindFirstFileW($0, &ffd) |
624 |
| - } |
625 |
| - if handle == INVALID_HANDLE_VALUE { |
626 |
| - throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [itemPath]) |
627 |
| - } |
628 |
| - defer { FindClose(handle) } |
629 |
| - |
630 |
| - repeat { |
631 |
| - let file = withUnsafePointer(to: &ffd.cFileName) { |
632 |
| - $0.withMemoryRebound(to: WCHAR.self, capacity: capacity) { |
633 |
| - String(decodingCString: $0, as: UTF16.self) |
634 |
| - } |
635 |
| - } |
| 631 | + let root = URL(fileURLWithPath: itemPath, isDirectory: true) |
| 632 | + try walk(directory: root) { (entry, attributes) in |
| 633 | + if entry == "." || entry == ".." { return } |
636 | 634 |
|
637 |
| - itemPath = "\(currentDir)\\\(file)" |
638 |
| - if ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY { |
639 |
| - if try !FileManager.default._fileSystemRepresentation(withPath: itemPath, { |
640 |
| - SetFileAttributesW($0, ffd.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
641 |
| - }) { |
642 |
| - throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file]) |
643 |
| - } |
644 |
| - } |
645 |
| - |
646 |
| - if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0) { |
647 |
| - if file != "." && file != ".." { |
648 |
| - dirStack.append(itemPath) |
649 |
| - } |
| 635 | + let isDirectory = attributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY && attributes & FILE_ATTRIBUTE_REPARSE_POINT == 0 |
| 636 | + let path = root.appendingPathComponent(entry, isDirectory: isDirectory) |
| 637 | + if isDirectory { |
| 638 | + dirStack.append(path.path) |
650 | 639 | } else {
|
651 |
| - guard alreadyConfirmed || shouldRemoveItemAtPath(itemPath, isURL: isURL) else { |
652 |
| - continue |
653 |
| - } |
654 |
| - if try !FileManager.default._fileSystemRepresentation(withPath: itemPath, DeleteFileW) { |
655 |
| - throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [file]) |
| 640 | + path.withUnsafeFileSystemRepresentation { |
| 641 | + guard alreadyConfirmed || shouldRemoveItemAtPath(path.path, isURL: isURL) else { |
| 642 | + return |
| 643 | + } |
| 644 | + |
| 645 | + "\\\\?\\\(String(cString: $0!))".withCString(encodedAs: UTF16.self) { |
| 646 | + if attributes & FILE_ATTRIBUTE_READONLY == FILE_ATTRIBUTE_READONLY { |
| 647 | + if !SetFileAttributesW($0, attributes & ~FILE_ATTRIBUTE_READONLY) { |
| 648 | + throw _NSErrorWithWindowsError(GetLastError(), reading: false, paths: [entry]) |
| 649 | + } |
| 650 | + } |
| 651 | + if !DeleteFileW($0) { |
| 652 | + throw _NSErrorWithWindowsError(GeteLastErrro(), reading: false, paths: [entry]) |
| 653 | + } |
| 654 | + } |
656 | 655 | }
|
657 | 656 | }
|
658 |
| - } while FindNextFileW(handle, &ffd) |
| 657 | + } |
659 | 658 | } catch {
|
660 | 659 | if !shouldProceedAfterError(error, removingItemAtPath: itemPath, isURL: isURL) {
|
661 | 660 | throw error
|
@@ -956,31 +955,14 @@ extension FileManager {
|
956 | 955 | }
|
957 | 956 |
|
958 | 957 | if _lastReturned.hasDirectoryPath && (level == 0 || !_options.contains(.skipsSubdirectoryDescendants)) {
|
959 |
| - var ffd = WIN32_FIND_DATAW() |
960 |
| - let capacity = MemoryLayout.size(ofValue: ffd.cFileName) |
961 |
| - |
962 |
| - let handle = (try? FileManager.default._fileSystemRepresentation(withPath: _lastReturned.path + "\\*") { |
963 |
| - FindFirstFileW($0, &ffd) |
964 |
| - }) ?? INVALID_HANDLE_VALUE |
965 |
| - if handle == INVALID_HANDLE_VALUE { return firstValidItem() } |
966 |
| - defer { FindClose(handle) } |
967 |
| - |
968 |
| - repeat { |
969 |
| - let file = withUnsafePointer(to: &ffd.cFileName) { |
970 |
| - $0.withMemoryRebound(to: WCHAR.self, capacity: capacity) { |
971 |
| - String(decodingCString: $0, as: UTF16.self) |
972 |
| - } |
973 |
| - } |
974 |
| - if file == "." || file == ".." { continue } |
975 |
| - if _options.contains(.skipsHiddenFiles) && |
976 |
| - ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN == FILE_ATTRIBUTE_HIDDEN { |
977 |
| - continue |
978 |
| - } |
979 |
| - |
980 |
| - let isDirectory = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY |
| 958 | + try walk(directory: _lastReturned) { (entry, attributes) in |
| 959 | + if entry == "." || entry == ".." { return } |
| 960 | + if _options.contains(.skipsHiddenFiles) && attributes & FILE_ATTRIBUTE_HIDDEN == FIND_ATTRIBUTE_HIDDEN { return } |
| 961 | + let isDirectory = attributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY && attributes & FILE_ATTRIBUTE_REPARSE_POINT == 0 |
981 | 962 | _stack.append(_lastReturned.appendingPathComponent(file, isDirectory: isDirectory))
|
982 |
| - } while FindNextFileW(handle, &ffd) |
| 963 | + } |
983 | 964 | }
|
| 965 | + |
984 | 966 | return firstValidItem()
|
985 | 967 | }
|
986 | 968 |
|
|
0 commit comments