@@ -589,7 +589,7 @@ extension FileManager {
589
589
590
590
if ffd. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY {
591
591
let readableAttributes = ffd. dwFileAttributes & DWORD ( bitPattern: ~ FILE_ATTRIBUTE_READONLY)
592
- guard file . withCString ( encodedAs: UTF16 . self, { SetFileAttributesW ( $0, readableAttributes) } ) else {
592
+ guard itemPath . withCString ( encodedAs: UTF16 . self, { SetFileAttributesW ( $0, readableAttributes) } ) else {
593
593
throw _NSErrorWithWindowsError ( GetLastError ( ) , reading: false , paths: [ file] )
594
594
}
595
595
}
@@ -684,10 +684,6 @@ extension FileManager {
684
684
return true
685
685
}
686
686
687
- internal func _compareFiles( withFileSystemRepresentation file1Rep: UnsafePointer < Int8 > , andFileSystemRepresentation file2Rep: UnsafePointer < Int8 > , size: Int64 , bufSize: Int ) -> Bool {
688
- NSUnimplemented ( )
689
- }
690
-
691
687
internal func _lstatFile( atPath path: String , withFileSystemRepresentation fsRep: UnsafePointer < Int8 > ? = nil ) throws -> stat {
692
688
let _fsRep : UnsafePointer < Int8 >
693
689
if fsRep == nil {
@@ -749,7 +745,86 @@ extension FileManager {
749
745
}
750
746
751
747
internal func _contentsEqual( atPath path1: String , andPath path2: String ) -> Bool {
752
- NSUnimplemented ( )
748
+ guard let path1Handle = path1. withCString ( encodedAs: UTF16 . self, {
749
+ CreateFileW ( $0, GENERIC_READ, DWORD ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) , nil ,
750
+ DWORD ( OPEN_EXISTING) , DWORD ( FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS) , nil )
751
+ } ) , path1Handle != INVALID_HANDLE_VALUE else {
752
+ return false
753
+ }
754
+
755
+ defer { CloseHandle ( path1Handle) }
756
+
757
+ guard let path2Handle = path2. withCString ( encodedAs: UTF16 . self, {
758
+ CreateFileW ( $0, GENERIC_READ, DWORD ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) , nil ,
759
+ DWORD ( OPEN_EXISTING) , DWORD ( FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS) , nil )
760
+ } ) , path2Handle != INVALID_HANDLE_VALUE else {
761
+ return false
762
+ }
763
+ defer { CloseHandle ( path2Handle) }
764
+
765
+ let file1Type = GetFileType ( path1Handle)
766
+ guard GetLastError ( ) == NO_ERROR else {
767
+ return false
768
+ }
769
+ let file2Type = GetFileType ( path2Handle)
770
+ guard GetLastError ( ) == NO_ERROR else {
771
+ return false
772
+ }
773
+
774
+ guard file1Type == FILE_TYPE_DISK, file2Type == FILE_TYPE_DISK else {
775
+ return false
776
+ }
777
+
778
+ var path1FileInfo = BY_HANDLE_FILE_INFORMATION ( )
779
+ var path2FileInfo = BY_HANDLE_FILE_INFORMATION ( )
780
+ guard GetFileInformationByHandle ( path1Handle, & path1FileInfo) ,
781
+ GetFileInformationByHandle ( path2Handle, & path2FileInfo) else {
782
+ return false
783
+ }
784
+
785
+ // If both paths point to the same volume/filenumber or they are both zero length
786
+ // then they are considered equal
787
+ if path1FileInfo. nFileIndexHigh == path2FileInfo. nFileIndexHigh
788
+ && path1FileInfo. nFileIndexLow == path2FileInfo. nFileIndexLow
789
+ && path1FileInfo. dwVolumeSerialNumber == path2FileInfo. dwVolumeSerialNumber {
790
+ return true
791
+ }
792
+
793
+ let path1Attrs = path1FileInfo. dwFileAttributes
794
+ let path2Attrs = path2FileInfo. dwFileAttributes
795
+ if path1Attrs & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
796
+ || path2Attrs & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT {
797
+ guard path1Attrs & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT
798
+ && path2Attrs & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT else {
799
+ return false
800
+ }
801
+ guard let pathDest1 = try ? _destinationOfSymbolicLink ( atPath: path1) ,
802
+ let pathDest2 = try ? _destinationOfSymbolicLink ( atPath: path2) else {
803
+ return false
804
+ }
805
+ return pathDest1 == pathDest2
806
+ } else if DWORD ( FILE_ATTRIBUTE_DIRECTORY) & path1Attrs == DWORD ( FILE_ATTRIBUTE_DIRECTORY)
807
+ || DWORD ( FILE_ATTRIBUTE_DIRECTORY) & path2Attrs == DWORD ( FILE_ATTRIBUTE_DIRECTORY) {
808
+ guard DWORD ( FILE_ATTRIBUTE_DIRECTORY) & path1Attrs == DWORD ( FILE_ATTRIBUTE_DIRECTORY)
809
+ && DWORD ( FILE_ATTRIBUTE_DIRECTORY) & path2Attrs == FILE_ATTRIBUTE_DIRECTORY else {
810
+ return false
811
+ }
812
+ return _compareDirectories ( atPath: path1, andPath: path2)
813
+ } else {
814
+ if path1FileInfo. nFileSizeHigh == 0 && path1FileInfo. nFileSizeLow == 0
815
+ && path2FileInfo. nFileSizeHigh == 0 && path2FileInfo. nFileSizeLow == 0 {
816
+ return true
817
+ }
818
+
819
+ let path1Fsr = fileSystemRepresentation ( withPath: path1)
820
+ defer { path1Fsr. deallocate ( ) }
821
+ let path2Fsr = fileSystemRepresentation ( withPath: path2)
822
+ defer { path2Fsr. deallocate ( ) }
823
+ return _compareFiles ( withFileSystemRepresentation: path1Fsr,
824
+ andFileSystemRepresentation: path2Fsr,
825
+ size: ( Int64 ( path1FileInfo. nFileSizeHigh) << 32 ) | Int64 ( path1FileInfo. nFileSizeLow) ,
826
+ bufSize: 0x1000 )
827
+ }
753
828
}
754
829
755
830
internal func _appendSymlinkDestination( _ dest: String , toPath: String ) -> String {
@@ -810,7 +885,7 @@ extension FileManager {
810
885
override func nextObject( ) -> Any ? {
811
886
func firstValidItem( ) -> URL ? {
812
887
while let url = _stack. popLast ( ) {
813
- if !FileManager. default. fileExists ( atPath: url. path, isDirectory : nil ) {
888
+ if !FileManager. default. fileExists ( atPath: url. path) {
814
889
guard let handler = _errorHandler,
815
890
handler ( url, _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ url. path] ) )
816
891
else { return nil }
@@ -823,15 +898,16 @@ extension FileManager {
823
898
}
824
899
825
900
// If we most recently returned a directory, decend into it
826
- var isDir : ObjCBool = false
827
- guard FileManager . default. fileExists ( atPath: _lastReturned. path, isDirectory: & isDir) else {
828
- guard let handler = _errorHandler,
901
+ guard let attrs = try ? FileManager . default. windowsFileAttributes ( atPath: _lastReturned. path) else {
902
+ guard let handler = _errorHandler,
829
903
handler ( _lastReturned, _NSErrorWithWindowsError ( GetLastError ( ) , reading: true , paths: [ _lastReturned. path] ) )
830
- else { return nil }
831
- return firstValidItem ( )
904
+ else { return nil }
905
+ return firstValidItem ( )
832
906
}
833
907
834
- if isDir. boolValue && ( level == 0 || !_options. contains ( . skipsSubdirectoryDescendants) ) {
908
+ let isDir = attrs. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_DIRECTORY) == DWORD ( FILE_ATTRIBUTE_DIRECTORY)
909
+ && attrs. dwFileAttributes & DWORD ( FILE_ATTRIBUTE_REPARSE_POINT) == 0
910
+ if isDir && ( level == 0 || !_options. contains ( . skipsSubdirectoryDescendants) ) {
835
911
var ffd = WIN32_FIND_DATAW ( )
836
912
let dirPath = joinPath ( prefix: _lastReturned. path, suffix: " * " )
837
913
let handle = dirPath. withCString ( encodedAs: UTF16 . self) {
0 commit comments