Skip to content

Commit a3de6aa

Browse files
Refactor stat functions in readdir code
1 parent 96fa5ba commit a3de6aa

File tree

1 file changed

+69
-81
lines changed

1 file changed

+69
-81
lines changed

core/src/Streamly/Internal/FileSystem/Posix/ReadDir.hsc

+69-81
Original file line numberDiff line numberDiff line change
@@ -273,72 +273,64 @@ isMetaDir dname = do
273273
then return True
274274
else return False
275275

276-
data GStatRes
277-
= GSIsMetaDir
278-
| GSIsRegDir
279-
| GSIsNotDir
280-
| GSIgnoreError Errno
281-
282-
{-# NOINLINE gstatDname #-}
283-
gstatDname
284-
:: ReadOptions -> PosixPath -> Ptr CChar -> IO GStatRes
285-
gstatDname conf parent dname = do
286-
isMeta <- liftIO $ isMetaDir dname
287-
if isMeta
288-
then pure GSIsMetaDir
289-
else do
290-
-- XXX We can create a pinned array right here since the next call pins
291-
-- it anyway.
292-
path <- appendCString parent dname
293-
Array.asCStringUnsafe (Path.toChunk path) $ \cStr -> do
294-
res <- stat (_followSymlinks conf) cStr
295-
case res of
296-
Right mode -> pure $
297-
if (mode == s_IFDIR)
298-
then GSIsRegDir
299-
else GSIsNotDir
300-
Left errno -> do
301-
if errno == eNOENT
302-
then unless (_ignoreNonExistingFiles conf) $
303-
throwErrno (errMsg path)
304-
else if errno == eACCES
305-
then unless (_ignoreInAccessibleFiles conf) $
306-
throwErrno (errMsg path)
307-
else if errno == eLOOP
308-
then unless (_ignoreSymlinkLoopErrors conf) $
309-
throwErrno (errMsg path)
310-
else throwErrno (errMsg path)
311-
pure $ GSIgnoreError errno
276+
data EntryType = EntryIsDir | EntryIsNotDir | EntryIgnored
277+
278+
{-# NOINLINE statEntryType #-}
279+
statEntryType
280+
:: ReadOptions -> PosixPath -> Ptr CChar -> IO EntryType
281+
statEntryType conf parent dname = do
282+
-- XXX We can create a pinned array right here since the next call pins
283+
-- it anyway.
284+
path <- appendCString parent dname
285+
Array.asCStringUnsafe (Path.toChunk path) $ \cStr -> do
286+
res <- stat (_followSymlinks conf) cStr
287+
case res of
288+
Right mode -> pure $
289+
if (mode == s_IFDIR)
290+
then EntryIsDir
291+
else EntryIsNotDir
292+
Left errno -> do
293+
if errno == eNOENT
294+
then unless (_ignoreNonExistingFiles conf) $
295+
throwErrno (errMsg path)
296+
else if errno == eACCES
297+
then unless (_ignoreInAccessibleFiles conf) $
298+
throwErrno (errMsg path)
299+
else if errno == eLOOP
300+
then unless (_ignoreSymlinkLoopErrors conf) $
301+
throwErrno (errMsg path)
302+
else throwErrno (errMsg path)
303+
pure $ EntryIgnored
312304
where
305+
313306
errMsg path =
314307
let pathStr = Path.toString_ path
315-
in "statDname: " ++ pathStr
308+
in "statEntryType: " ++ pathStr
316309

317-
-- | Checks if dname is a directory and additionaly returns if dname is a meta
318-
-- directory.
319-
{-# INLINE checkDirStatus #-}
320-
checkDirStatus
310+
-- | Checks if dname is a directory, not dir or should be ignored.
311+
{-# INLINE getEntryType #-}
312+
getEntryType
321313
:: ReadOptions
322-
-> PosixPath -> Ptr CChar -> #{type unsigned char} -> IO GStatRes
314+
-> PosixPath -> Ptr CChar -> #{type unsigned char} -> IO EntryType
315+
getEntryType conf parent dname dtype = do
316+
let needStat =
323317
#ifdef FORCE_LSTAT_READDIR
324-
checkDirStatus conf parent dname _ =
325-
gstatDname conf parent dname
318+
True
326319
#else
327-
checkDirStatus conf parent dname dtype =
328-
if dtype == (#const DT_DIR)
329-
then do
330-
isMeta <- liftIO $ isMetaDir dname
331-
pure $ if isMeta then GSIsMetaDir else GSIsRegDir
332-
else if dtype == (#const DT_LNK)
333-
then
334-
if _followSymlinks conf
335-
then gstatDname conf parent dname
336-
else pure GSIsNotDir
337-
else if dtype /= #const DT_UNKNOWN
338-
then pure GSIsNotDir
339-
else gstatDname conf parent dname
320+
(dtype == (#const DT_LNK) && _followSymlinks conf)
321+
|| dtype == #const DT_UNKNOWN
340322
#endif
341323

324+
if dtype /= (#const DT_DIR) && not needStat
325+
then pure EntryIsNotDir
326+
else do
327+
isMeta <- liftIO $ isMetaDir dname
328+
if isMeta
329+
then pure EntryIgnored
330+
else if dtype == (#const DT_DIR)
331+
then pure EntryIsDir
332+
else statEntryType conf parent dname
333+
342334
-------------------------------------------------------------------------------
343335
-- streaming reads
344336
-------------------------------------------------------------------------------
@@ -376,12 +368,11 @@ readDirStreamEither confMod (curdir, (DirStream dirp)) = loop
376368
-- fromPtrN, but it is not straightforward because the reclen is
377369
-- padded to 8-byte boundary.
378370
name <- Array.fromCString (castPtr dname)
379-
gsRes <- checkDirStatus conf curdir dname dtype
380-
case gsRes of
381-
GSIsRegDir -> return (Just (Left (mkPath name)))
382-
GSIsNotDir -> return (Just (Right (mkPath name)))
383-
-- Loop if it's a meta directory or an error that we can ignore
384-
_ -> loop
371+
etype <- getEntryType conf curdir dname dtype
372+
case etype of
373+
EntryIsDir -> return (Just (Left (mkPath name)))
374+
EntryIsNotDir -> return (Just (Right (mkPath name)))
375+
EntryIgnored -> loop
385376
else do
386377
errno <- getErrno
387378
if (errno == eINTR)
@@ -515,9 +506,9 @@ readEitherChunks confMod alldirs =
515506
dtype :: #{type unsigned char} <-
516507
liftIO $ #{peek struct dirent, d_type} dentPtr
517508

518-
gsRes <- liftIO $ checkDirStatus conf curdir dname dtype
519-
case gsRes of
520-
GSIsRegDir -> do
509+
etype <- liftIO $ getEntryType conf curdir dname dtype
510+
case etype of
511+
EntryIsDir -> do
521512
path <- liftIO $ appendCString curdir dname
522513
let dirs1 = path : dirs
523514
ndirs1 = ndirs + 1
@@ -526,7 +517,7 @@ readEitherChunks confMod alldirs =
526517
(ChunkStreamLoop curdir xs dirp [] 0 files nfiles)
527518
else return $ Skip
528519
(ChunkStreamLoop curdir xs dirp dirs1 ndirs1 files nfiles)
529-
GSIsNotDir -> do
520+
EntryIsNotDir -> do
530521
path <- liftIO $ appendCString curdir dname
531522
let files1 = path : files
532523
nfiles1 = nfiles + 1
@@ -535,8 +526,7 @@ readEitherChunks confMod alldirs =
535526
(ChunkStreamLoop curdir xs dirp dirs ndirs [] 0)
536527
else return $ Skip
537528
(ChunkStreamLoop curdir xs dirp dirs ndirs files1 nfiles1)
538-
-- Loop if it's a meta directory or an error that we can ignore
539-
_ -> return $ Skip st
529+
EntryIgnored -> return $ Skip st
540530
else do
541531
errno <- liftIO getErrno
542532
if (errno == eINTR)
@@ -684,9 +674,9 @@ readEitherByteChunks confMod alldirs =
684674
-- because it has a StreamK in the middle.
685675
-- Keep the file check first as it is more likely
686676

687-
gsRes <- liftIO $ checkDirStatus conf curdir dname dtype
688-
case gsRes of
689-
GSIsNotDir -> do
677+
etype <- liftIO $ getEntryType conf curdir dname dtype
678+
case etype of
679+
EntryIsNotDir -> do
690680
r <- copyToBuf mbarr pos curdir dname
691681
case r of
692682
Just pos1 ->
@@ -703,7 +693,7 @@ readEitherByteChunks confMod alldirs =
703693
else
704694
return $ Skip
705695
(ChunkStreamByteLoopPending dname curdir xs dirp mbarr pos)
706-
GSIsRegDir -> do
696+
EntryIsDir -> do
707697
path <- liftIO $ appendCString curdir dname
708698
let dirs1 = path : dirs
709699
ndirs1 = ndirs + 1
@@ -718,8 +708,7 @@ readEitherByteChunks confMod alldirs =
718708
-- otherwise skip.
719709
return $ Yield (Left dirs1)
720710
(ChunkStreamByteLoopPending dname curdir xs dirp mbarr pos)
721-
-- Loop if it's a meta directory or an error that we can ignore
722-
_ -> return $ Skip st
711+
EntryIgnored -> return $ Skip st
723712
else do
724713
errno <- liftIO getErrno
725714
if (errno == eINTR)
@@ -843,9 +832,9 @@ readEitherByteChunksAt confMod (ppath, alldirs) =
843832
liftIO $ #{peek struct dirent, d_type} dentPtr
844833

845834
-- Keep the file check first as it is more likely
846-
gsRes <- liftIO $ checkDirStatus conf curdir dname dtype
847-
case gsRes of
848-
GSIsNotDir -> do
835+
etype <- liftIO $ getEntryType conf curdir dname dtype
836+
case etype of
837+
EntryIsNotDir -> do
849838
r <- copyToBuf mbarr pos curdir dname
850839
case r of
851840
Just pos1 ->
@@ -856,7 +845,7 @@ readEitherByteChunksAt confMod (ppath, alldirs) =
856845
return $ Skip
857846
(ByteChunksAtRealloc
858847
dname pfd dirp curdir xs dirs ndirs mbarr pos)
859-
GSIsRegDir -> do
848+
EntryIsDir -> do
860849
arr <- Array.fromCString (castPtr dname)
861850
let path = Path.unsafeFromChunk arr
862851
let dirs1 = path : dirs
@@ -882,8 +871,7 @@ readEitherByteChunksAt confMod (ppath, alldirs) =
882871
return $ Skip
883872
(ByteChunksAtRealloc
884873
dname pfd dirp curdir xs dirs1 ndirs1 mbarr pos)
885-
-- Loop if it's a meta directory or an error that we can ignore
886-
_ -> return $ Skip st
874+
EntryIgnored -> return $ Skip st
887875
else do
888876
errno <- liftIO getErrno
889877
if (errno == eINTR)

0 commit comments

Comments
 (0)