@@ -47,6 +47,8 @@ import System.Directory.OsPath
47
47
( listDirectory , doesDirectoryExist , getModificationTime
48
48
, pathIsSymbolicLink , getSymbolicLinkTarget
49
49
, Permissions (.. ), getPermissions , getFileSize )
50
+ import System.Directory.OsPath.FileType as FT
51
+ import System.Directory.OsPath.Streaming
50
52
import Data.Time.Clock
51
53
( UTCTime )
52
54
import Data.Time.Clock.POSIX
@@ -242,27 +244,33 @@ packSymlinkEntry' filepath tarpath = do
242
244
-- the behaviour is undefined.
243
245
--
244
246
getDirectoryContentsRecursive :: OsPath -> IO [OsPath ]
245
- getDirectoryContentsRecursive dir0 =
246
- fmap (drop 1 ) (recurseDirectories dir0 [mempty ])
247
-
248
- recurseDirectories :: OsPath -> [OsPath ] -> IO [OsPath ]
249
- recurseDirectories _ [] = return []
250
- recurseDirectories base (dir: dirs) = unsafeInterleaveIO $ do
251
- (files, dirs') <- collect [] [] =<< listDirectory (base </> dir)
252
-
253
- files' <- recurseDirectories base (dirs' ++ dirs)
254
- return (dir : files ++ files')
255
-
247
+ getDirectoryContentsRecursive base = recurseDirectories [mempty ]
256
248
where
257
- collect files dirs' [] = return (reverse files, reverse dirs')
258
- collect files dirs' (entry: entries) = do
259
- let dirEntry = dir </> entry
260
- dirEntry' = FilePath.Native. addTrailingPathSeparator dirEntry
261
- isDirectory <- doesDirectoryExist (base </> dirEntry)
262
- isSymlink <- pathIsSymbolicLink (base </> dirEntry)
263
- if isDirectory && not isSymlink
264
- then collect files (dirEntry': dirs') entries
265
- else collect (dirEntry: files) dirs' entries
249
+ recurseDirectories :: [OsPath ] -> IO [OsPath ]
250
+ recurseDirectories [] = pure []
251
+ recurseDirectories (path : paths) = do
252
+ stream <- openDirStream (base </> path)
253
+ recurseStream path stream paths
254
+
255
+ recurseStream :: OsPath -> DirStream -> [OsPath ] -> IO [OsPath ]
256
+ recurseStream currPath currStream rest = go
257
+ where
258
+ go = unsafeInterleaveIO $ do
259
+ mfn <- readDirStream currStream
260
+ case mfn of
261
+ Nothing -> do
262
+ closeDirStream currStream
263
+ recurseDirectories rest
264
+ Just fn -> do
265
+ ty <- getFileType basePathFn
266
+ case ty of
267
+ FT. Directory ->
268
+ (FilePath.Native. addTrailingPathSeparator pathFn : ) <$>
269
+ recurseStream currPath currStream (pathFn : rest)
270
+ _ -> (pathFn : ) <$> go
271
+ where
272
+ pathFn = currPath </> fn
273
+ basePathFn = base </> pathFn
266
274
267
275
getModTime :: OsPath -> IO EpochTime
268
276
getModTime path = do
0 commit comments