Skip to content

Commit 8647fb6

Browse files
Replace unsafeJoin with appendW16CString in Win Readdir
1 parent 4ab01db commit 8647fb6

2 files changed

Lines changed: 43 additions & 39 deletions

File tree

core/src/Streamly/Internal/FileSystem/Path/Common.hs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,7 @@ module Streamly.Internal.FileSystem.Path.Common
5959
, unsafeAppend
6060
, appendCString
6161
, appendCString'
62-
, appendCWString
63-
, appendCWString'
62+
, appendCStringWith
6463
, unsafeJoinPaths
6564
-- , joinRoot -- XXX append should be enough, see joinRootBody
6665

@@ -128,7 +127,7 @@ import Data.Function ((&))
128127
import Data.Functor.Identity (Identity(..))
129128
import Data.Word (Word8, Word16)
130129
import Foreign (castPtr)
131-
import Foreign.C (CString, CSize(..), CWchar, CWString)
130+
import Foreign.C (CString, CSize(..))
132131
import GHC.Base (unsafeChr, Addr#)
133132
import GHC.Ptr (Ptr(..))
134133
import Language.Haskell.TH (Q, Exp)
@@ -1541,19 +1540,6 @@ appendCString' :: OS -> Array Word8 -> CString -> IO (Array Word8)
15411540
appendCString' os arr cstr =
15421541
appendCStringWith MutArray.emptyOf' c_strlen_pinned os arr (castPtr cstr)
15431542

1544-
foreign import ccall unsafe "wchar.h wcslen" c_wcslen_pinned
1545-
:: Addr# -> IO CSize
1546-
1547-
-- | NOTE: CWchar is 16-bit wide on Windows and 32-bit wide on Posix. wcslen is
1548-
-- available on both Posix and Windows and counts accordingly in units of
1549-
-- 2-bytes or 4-bytes.
1550-
{-# INLINE appendCWString #-}
1551-
appendCWString :: OS -> Array CWchar -> CWString -> IO (Array CWchar)
1552-
appendCWString = appendCStringWith MutArray.emptyOf c_wcslen_pinned
1553-
1554-
{-# INLINE appendCWString' #-}
1555-
appendCWString' :: OS -> Array CWchar -> CWString -> IO (Array CWchar)
1556-
appendCWString' = appendCStringWith MutArray.emptyOf' c_wcslen_pinned
15571543

15581544
{-# INLINE doAppend #-}
15591545
doAppend :: (Unbox a, Integral a) => OS -> Array a -> Array a -> Array a

core/src/Streamly/Internal/Syscall/Windows/ReadDir.hsc

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
-- Maintainer : streamly@composewell.com
77
-- Portability : GHC
88

9+
{-# LANGUAGE UnliftedFFITypes #-}
10+
911
module Streamly.Internal.Syscall.Windows.ReadDir
1012
(
1113
#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
@@ -29,6 +31,7 @@ import Control.Monad.Catch (MonadCatch)
2931
import Control.Monad.IO.Class (MonadIO(..))
3032
import Data.Char (ord, isSpace)
3133
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
34+
import GHC.Base (Addr#)
3235
import Foreign.C
3336
( CInt(..), CSize(..), CWchar(..), Errno(..)
3437
, errnoToIOError, peekCWString
@@ -44,8 +47,10 @@ import Streamly.Internal.FileSystem.WindowsPath (WindowsPath(..))
4447
import System.IO.Error (ioeSetErrorString)
4548

4649
import qualified Streamly.Internal.Data.Array as Array
50+
import qualified Streamly.Internal.Data.MutArray as MutArray
4751
import qualified Streamly.Internal.Data.MutByteArray as MutByteArray
4852
import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
53+
import qualified Streamly.Internal.FileSystem.Path.Common as PathC
4954
import qualified Streamly.Internal.FileSystem.WindowsPath as Path
5055
import qualified System.Win32 as Win32 (failWith)
5156

@@ -95,9 +100,12 @@ foreign import ccall unsafe "windows.h LocalFree"
95100
localFree :: Ptr a -> IO (Ptr a)
96101

97102
------------------------------------------------------------------------------
98-
-- Haskell C APIs
103+
-- FFI imports/Haskell C APIs
99104
------------------------------------------------------------------------------
100105

106+
foreign import ccall unsafe "string.h memcpy" c_memcpy
107+
:: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
108+
101109
foreign import ccall unsafe "maperrno_func" -- in base/cbits/Win32Utils.c
102110
c_maperrno_func :: ErrCode -> IO Errno
103111

@@ -144,6 +152,32 @@ failIf p wh act = do
144152
iNVALID_HANDLE_VALUE :: HANDLE
145153
iNVALID_HANDLE_VALUE = castUINTPtrToPtr maxBound
146154

155+
------------------------------------------------------------------------------
156+
-- Path string manipulation
157+
------------------------------------------------------------------------------
158+
159+
foreign import ccall unsafe "wchar.h wcslen" c_wcslen
160+
:: Ptr CWchar -> IO CSize
161+
162+
foreign import ccall unsafe "wchar.h wcslen" c_wcslen_pinned
163+
:: Addr# -> IO CSize
164+
165+
-- This is defined here and not in Path module because wcslen is a platform
166+
-- specific function and uses 32-bit wide chars on posix and 16-bit wide chars
167+
-- on Windows. We cannot have it in WindowsPath module because that module is
168+
-- plaform agnostic and works on Posix as well.
169+
--
170+
{-# INLINE appendW16CString #-}
171+
appendW16CString :: WindowsPath -> Ptr CWchar -> IO WindowsPath
172+
appendW16CString (WindowsPath arr) str =
173+
fmap WindowsPath
174+
$ PathC.appendCStringWith
175+
MutArray.emptyOf
176+
c_wcslen_pinned
177+
PathC.Windows
178+
arr
179+
(castPtr str)
180+
147181
------------------------------------------------------------------------------
148182
-- Dir stream implementation
149183
------------------------------------------------------------------------------
@@ -358,11 +392,8 @@ readEitherChunks _confMod alldirs =
358392
if isMeta
359393
then return $ Skip st
360394
else do
361-
arr <- liftIO $ Array.fromW16CString dname
362-
let path =
363-
Path.unsafeJoin curdir
364-
(Path.unsafeFromArray arr)
365-
dirs1 = path : dirs
395+
path <- liftIO $ appendW16CString curdir dname
396+
let dirs1 = path : dirs
366397
ndirs1 = ndirs + 1
367398
if ndirs1 >= dirMax
368399
then return $ Yield (Left dirs1)
@@ -371,11 +402,8 @@ readEitherChunks _confMod alldirs =
371402
(ChunkStreamLoop
372403
curdir xs ds dirs1 ndirs1 files nfiles)
373404
else do
374-
arr <- liftIO $ Array.fromW16CString dname
375-
let path =
376-
Path.unsafeJoin curdir
377-
(Path.unsafeFromArray arr)
378-
files1 = path : files
405+
path <- liftIO $ appendW16CString curdir dname
406+
let files1 = path : files
379407
nfiles1 = nfiles + 1
380408
if nfiles1 >= fileMax
381409
then return $ Yield (Right files1)
@@ -392,12 +420,6 @@ readEitherChunks _confMod alldirs =
392420
-- Chunked byte-buffered reads
393421
------------------------------------------------------------------------------
394422

395-
foreign import ccall unsafe "string.h memcpy" c_memcpy
396-
:: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
397-
398-
foreign import ccall unsafe "wchar.h wcslen" c_wcslen
399-
:: Ptr CWchar -> IO CSize
400-
401423
-- Split a list in half.
402424
splitHalf :: [a] -> ([a], [a])
403425
splitHalf xxs = split xxs xxs
@@ -430,8 +452,6 @@ data ChunkStreamByteState =
430452
MutByteArray
431453
Int
432454

433-
-- TODO: instead of unsafeJoin use appendCWString
434-
--
435455
-- NOTE: Unlike posix on Windows the file attribute to determine whether it is
436456
-- a directory or not is always available so we do not need the code to handle
437457
-- the case when they are not available, on Posix we need to use stat
@@ -597,10 +617,8 @@ readEitherByteChunks _confMod alldirs =
597617

598618
{-# INLINE handleDirEnt #-}
599619
handleDirEnt pos dname = do
600-
arr <- liftIO $ Array.fromW16CString dname
601-
let path =
602-
Path.unsafeJoin curdir (Path.unsafeFromArray arr)
603-
dirs1 = path : dirs
620+
path <- liftIO $ appendW16CString curdir dname
621+
let dirs1 = path : dirs
604622
r <- copyToBuf mbarr pos curdir dname
605623
case r of
606624
Just pos1 -> goInner dirs1 pos1

0 commit comments

Comments
 (0)