@@ -168,32 +168,41 @@ public struct FileIterator: Sequence, IteratorProtocol {
168168///   exist or is not a supported file type. If `followSymlinks` is `true`, the returned URL may be
169169///   different from the given URL; otherwise, it will be the same.
170170private  func  fileAndType( at url:  URL ,  followSymlinks:  Bool )  ->  ( URL ,  FileAttributeType ) ? { 
171-   func  typeOfFile( at url:  URL )  ->  FileAttributeType ? { 
172-     // We cannot use `URL.resourceValues(forKeys:)` here because it appears to behave incorrectly on
173-     // Linux.
174-     return  try ? FileManager . default. attributesOfItem ( atPath:  url. path) [ . type]  as?  FileAttributeType 
171+   var  url  =  url
172+   if  followSymlinks { 
173+     url =  realPath ( of:  url) 
175174  } 
176175
177-   guard  var  fileType =  typeOfFile ( at:  url)  else  { 
176+   // We cannot use `URL.resourceValues(forKeys:)` here because it appears to behave incorrectly on
177+   // Linux.
178+   guard 
179+     let  type = 
180+       try ? FileManager . default. attributesOfItem ( atPath:  url. path) [ . type]  as?  FileAttributeType 
181+   else  { 
178182    return  nil 
179183  } 
180184
181-   // We would use `standardizedFileURL.path` here as we do in the iterator above to ensure that 
182-   // path components like `.` and `..` are resolved, but the standardized URLs returned by 
183-   // Foundation pre-Swift-6.0 resolve symlinks. This causes the file type of a URL and its 
184-   // standardized path to not match .
185-    var   visited :   Set < String >   =   [ url . absoluteString ] 
186-    var   url   =  url 
187-    while  followSymlinks && fileType  ==   . typeSymbolicLink , 
188-      let  destination  =   try ?   FileManager . default . destinationOfSymbolicLink ( atPath :  url . path ) 
189-    { 
190-     url  =   URL ( fileURLWithPath :  destination ,  relativeTo :  url ) 
191-     // If this URL is in the visited set, we must have a symlink cycle. Ignore it gracefully. 
192-     guard  !visited . contains ( url . absoluteString ) ,   let  newType  =  typeOfFile ( at :  url )  else  { 
193-       return  nil 
185+   return   ( url ,  type ) 
186+ } 
187+ 
188+ /// Assuming the given URL is a file URL, resolves all symlinks in its path .
189+ /// 
190+ /// - Note: We need this because `URL.resolvingSymlinksInPath()` not only resolves symlinks but also standardizes the 
191+ ///   path by stripping away `private` prefixes. 
192+ @ _spi ( Internal ) 
193+ public   func  realPath ( of url :   URL )   ->   URL  { 
194+   #if canImport(Darwin )
195+   return  url . path . withCString   {  path  in 
196+     guard  let  realpath  =  Darwin . realpath ( path ,   nil )  else  { 
197+       return  url 
194198    } 
195-     visited. insert ( url. absoluteString) 
196-     fileType =  newType
199+     let  result  =  URL ( fileURLWithPath:  String ( cString:  realpath) ) 
200+     free ( realpath) 
201+     return  result
197202  } 
198-   return  ( url,  fileType) 
203+   #else 
204+   // Non-Darwin platforms don't have the `/private` stripping issue, so we can just use `self.resolvingSymlinksInPath`
205+   // here.
206+   return  url. resolvingSymlinksInPath ( ) 
207+   #endif 
199208} 
0 commit comments