@@ -652,14 +652,15 @@ extension FileManager {
652
652
var _options : FileManager . DirectoryEnumerationOptions
653
653
var _errorHandler : ( ( URL , Error ) -> Bool ) ?
654
654
var _stack : [ URL ]
655
- var _current : URL ?
655
+ var _current : URL
656
656
var _rootDepth : Int
657
657
658
658
init ( url: URL , options: FileManager . DirectoryEnumerationOptions , errorHandler: ( /* @escaping */ ( URL , Error ) -> Bool ) ? ) {
659
659
_options = options
660
660
_errorHandler = errorHandler
661
- _stack = [ url ]
661
+ _stack = [ ]
662
662
_rootDepth = url. pathComponents. count
663
+ _current = url
663
664
}
664
665
665
666
override func nextObject( ) -> Any ? {
@@ -689,27 +690,52 @@ extension FileManager {
689
690
} while FindNextFileW ( h, & ffd)
690
691
return files
691
692
}
692
- while let url = _stack. popLast ( ) {
693
- if url. hasDirectoryPath && !_options. contains ( . skipsSubdirectoryDescendants) {
694
- guard let dirContents = contentsOfDir ( directory: url) ? . reversed ( ) else {
695
- if let handler = _errorHandler {
696
- let dirFSR = url. withUnsafeFileSystemRepresentation { $0. flatMap { fsr in String ( utf8String: fsr) } }
697
- let keepGoing = handler ( URL ( fileURLWithPath: dirFSR ?? " " ) ,
698
- _NSErrorWithWindowsError ( GetLastError ( ) , reading: true ) )
699
- if !keepGoing { return nil }
700
- }
701
- continue
702
- }
703
- _stack. append ( contentsOf: dirContents)
693
+
694
+ func findFirstValidFile( ) -> URL ? {
695
+ while let url = _stack. popLast ( ) {
696
+ let dirFSR = url. withUnsafeFileSystemRepresentation { $0. flatMap { fsr in String ( utf8String: fsr) } } ?? " "
697
+ if !FileManager. default. fileExists ( atPath: dirFSR, isDirectory: nil ) {
698
+ if let handler = _errorHandler {
699
+ let keepGoing = handler ( URL ( fileURLWithPath: dirFSR) ,
700
+ _NSErrorWithWindowsError ( GetLastError ( ) , reading: true ) )
701
+ if !keepGoing { return nil }
702
+ }
703
+ continue
704
704
}
705
+
705
706
_current = url
706
- return url
707
+ return _current
708
+ }
709
+ return nil
707
710
}
708
- return nil
711
+
712
+ var isDir : ObjCBool = false
713
+ let dirFSR = _current. withUnsafeFileSystemRepresentation { $0. flatMap { fsr in String ( utf8String: fsr) } } ?? " "
714
+ guard FileManager . default. fileExists ( atPath: dirFSR, isDirectory: & isDir) else {
715
+ if let handler = _errorHandler {
716
+ let keepGoing = handler ( URL ( fileURLWithPath: dirFSR) ,
717
+ _NSErrorWithWindowsError ( GetLastError ( ) , reading: true ) )
718
+ return keepGoing ? findFirstValidFile ( ) : nil
719
+ }
720
+ return nil
721
+ }
722
+
723
+ if isDir. boolValue && !_options. contains ( . skipsSubdirectoryDescendants) {
724
+ if let dirContents = contentsOfDir ( directory: _current) ? . reversed ( ) {
725
+ _stack. append ( contentsOf: dirContents)
726
+ } else {
727
+ if let handler = _errorHandler {
728
+ let keepGoing = handler ( URL ( fileURLWithPath: dirFSR) ,
729
+ _NSErrorWithWindowsError ( GetLastError ( ) , reading: true ) )
730
+ if !keepGoing { return nil }
731
+ }
732
+ }
733
+ }
734
+ return findFirstValidFile ( )
709
735
}
710
736
711
737
override var level : Int {
712
- return _rootDepth - ( _current? . pathComponents. count ?? _rootDepth)
738
+ return _current. pathComponents. count - _rootDepth
713
739
}
714
740
715
741
override func skipDescendants( ) {
@@ -733,8 +759,7 @@ extension FileManager.NSPathDirectoryEnumerator {
733
759
return nil
734
760
}
735
761
736
- var relativePath = UnsafeMutableBufferPointer< WCHAR> . allocate( capacity: Int ( MAX_PATH) )
737
- defer { relativePath. deallocate ( ) }
762
+ var relativePath : [ WCHAR ] = Array < WCHAR > ( repeating: 0 , count: Int ( MAX_PATH) )
738
763
func withURLCString< Result> ( url: URL , _ f: ( UnsafePointer < WCHAR > ) -> Result ? ) -> Result ? {
739
764
return url. withUnsafeFileSystemRepresentation { fsr in
740
765
( fsr. flatMap { String ( utf8String: $0) } ) ? . withCString ( encodedAs: UTF16 . self) { f ( $0) }
@@ -747,12 +772,14 @@ extension FileManager.NSPathDirectoryEnumerator {
747
772
guard fromAttrs != INVALID_FILE_ATTRIBUTES, toAttrs != INVALID_FILE_ATTRIBUTES else {
748
773
return false
749
774
}
750
- return PathRelativePathToW ( relativePath. baseAddress , pszFrom, fromAttrs, pszTo, toAttrs)
775
+ return PathRelativePathToW ( & relativePath, pszFrom, fromAttrs, pszTo, toAttrs)
751
776
}
752
- } ) == true , let ( path, _) = String . decodeCString ( relativePath. baseAddress , as: UTF16 . self) else {
777
+ } ) == true , let ( path, _) = String . decodeCString ( & relativePath, as: UTF16 . self) else {
753
778
return nil
754
779
}
755
- _currentItemPath = path
780
+ // PathRelativePathToW always prepends a ".\" to the path. Drop it to
781
+ // match the POSIX implementation
782
+ _currentItemPath = path. dropFirst ( 2 )
756
783
return _currentItemPath
757
784
}
758
785
0 commit comments