@@ -23,8 +23,8 @@ package fs2
23
23
package io
24
24
package file
25
25
26
- import cats .effect . kernel . Async
27
- import cats .effect .kernel .Resource
26
+ import cats .Traverse
27
+ import cats .effect .kernel .{ Async , Resource }
28
28
import cats .syntax .all ._
29
29
import fs2 .io .file .Files .UnsealedFiles
30
30
import fs2 .io .internal .facade
@@ -369,6 +369,54 @@ private[fs2] trait FilesCompanionPlatform {
369
369
override def size (path : Path ): F [Long ] =
370
370
stat(path).map(_.size.toString.toLong)
371
371
372
+ override def walkWithAttributes (start : Path , options : WalkOptions ): Stream [F , PathInfo ] = {
373
+
374
+ def go (
375
+ start : Path ,
376
+ maxDepth : Int ,
377
+ ancestry : List [Either [Path , FileKey ]]
378
+ ): Stream [F , PathInfo ] =
379
+ Stream .eval(getBasicFileAttributes(start, followLinks = false )).mask.flatMap { attr =>
380
+ Stream .emit(PathInfo (start, attr)) ++ {
381
+ if (maxDepth == 0 ) Stream .empty
382
+ else if (attr.isDirectory)
383
+ list(start).mask.flatMap { path =>
384
+ go(path, maxDepth - 1 , attr.fileKey.toRight(start) :: ancestry)
385
+ }
386
+ else if (attr.isSymbolicLink && options.followLinks)
387
+ Stream .eval(getBasicFileAttributes(start, followLinks = true )).mask.flatMap { attr =>
388
+ val fileKey = attr.fileKey
389
+ val isCycle = Traverse [List ].existsM(ancestry) {
390
+ case Right (ancestorKey) => F .pure(fileKey.contains(ancestorKey))
391
+ case Left (ancestorPath) => isSameFile(start, ancestorPath)
392
+ }
393
+
394
+ Stream .eval(isCycle).flatMap { isCycle =>
395
+ if (! isCycle)
396
+ list(start).mask.flatMap { path =>
397
+ go(path, maxDepth - 1 , attr.fileKey.toRight(start) :: ancestry)
398
+ }
399
+ else if (options.allowCycles)
400
+ Stream .empty
401
+ else
402
+ Stream .raiseError(new FileSystemLoopException (start.toString))
403
+ }
404
+
405
+ }
406
+ else
407
+ Stream .empty
408
+ }
409
+ }
410
+
411
+ go(
412
+ start,
413
+ options.maxDepth,
414
+ Nil
415
+ )
416
+ .chunkN(options.chunkSize)
417
+ .flatMap(Stream .chunk)
418
+ }
419
+
372
420
override def writeAll (path : Path , _flags : Flags ): Pipe [F , Byte , Nothing ] =
373
421
in =>
374
422
in.through {
0 commit comments