Skip to content

Commit

Permalink
Unfix a few things in Event.Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
adithyaov committed Oct 16, 2024
1 parent 0149863 commit e0348e6
Showing 1 changed file with 27 additions and 19 deletions.
46 changes: 27 additions & 19 deletions src/Streamly/Internal/FileSystem/Event/Windows.hs
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ where

import Data.Bits ((.|.), (.&.), complement)
import Data.List.NonEmpty (NonEmpty)
import Foreign.C.String (peekCWStringLen)
import Foreign.Marshal.Alloc (alloca, allocaBytes)
import Foreign.Storable (peekByteOff)
import Foreign.Ptr (Ptr, FunPtr, castPtr, nullPtr, nullFunPtr, plusPtr)
import System.IO.Unsafe (unsafePerformIO)
import System.Win32.File
( FileNotificationFlag
, LPOVERLAPPED
Expand Down Expand Up @@ -121,7 +123,6 @@ import qualified Data.List.NonEmpty as NonEmpty
import qualified Streamly.Data.Fold as Fold
import qualified Streamly.Data.Stream as S
import qualified Streamly.Data.Stream.Prelude as S
import qualified Streamly.Internal.Data.Array as Array
import qualified Streamly.Internal.FileSystem.Path as Path

-- | Watch configuration, used to specify the events of interest and the
Expand Down Expand Up @@ -278,28 +279,27 @@ getConfigRecMode Config{..} = watchRec

data Event = Event
{ eventFlags :: DWORD
, eventRelPath :: Path
, eventRootPath :: Path
, eventRelPath :: String
, eventRootPath :: String
, totalBytes :: DWORD
}
} deriving (Show, Ord, Eq)

-- For reference documentation see:
--
-- See https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-file_notify_information
data FILE_NOTIFY_INFORMATION = FILE_NOTIFY_INFORMATION
{ fniNextEntryOffset :: DWORD
, fniAction :: DWORD
, fniFileName :: Path
}
, fniFileName :: String
} deriving Show

type LPOVERLAPPED_COMPLETION_ROUTINE =
FunPtr ((DWORD, DWORD, LPOVERLAPPED) -> IO ())

-- | A handle for a watch.
getWatchHandle :: Path -> IO (HANDLE, Path)
getWatchHandle :: FilePath -> IO (HANDLE, FilePath)
getWatchHandle dir = do
let dirStr = Path.toString dir
h <- createFile dirStr
h <- createFile dir
-- Access mode
fILE_LIST_DIRECTORY
-- Share mode
Expand Down Expand Up @@ -350,12 +350,17 @@ peekFNI buf = do
neof <- peekByteOff buf 0
acti <- peekByteOff buf 4
fnle <- peekByteOff buf 8
fnam0 <- Array.fromPtrN fnle (buf `plusPtr` 12)
fnam <- Path.fromChunk fnam0
-- Note: The path is UTF-16 encoded C WChars, peekCWStringLen converts
-- UTF-16 to UTF-32 Char String
fnam <- peekCWStringLen
-- start of array
(buf `plusPtr` 12,
-- fnle is the length in *bytes*, and a WCHAR is 2 bytes
fromEnum (fnle :: DWORD) `div` 2)
return $ FILE_NOTIFY_INFORMATION neof acti fnam

readChangeEvents ::
Ptr FILE_NOTIFY_INFORMATION -> Path -> DWORD -> IO [Event]
Ptr FILE_NOTIFY_INFORMATION -> String -> DWORD -> IO [Event]
readChangeEvents pfni root bytesRet = do
fni <- peekFNI pfni
let entry = Event
Expand All @@ -372,7 +377,7 @@ readChangeEvents pfni root bytesRet = do
return $ entry : entries

readDirectoryChanges ::
Path -> HANDLE -> Bool -> FileNotificationFlag -> IO [Event]
String -> HANDLE -> Bool -> FileNotificationFlag -> IO [Event]
readDirectoryChanges root h wst mask = do
let maxBuf = 63 * 1024
allocaBytes maxBuf $ \buffer -> do
Expand All @@ -399,7 +404,7 @@ fILE_ACTION_RENAMED_OLD_NAME = 4
fILE_ACTION_RENAMED_NEW_NAME :: FileAction
fILE_ACTION_RENAMED_NEW_NAME = 5

eventStreamAggr :: (HANDLE, Path, Config) -> Stream IO Event
eventStreamAggr :: (HANDLE, FilePath, Config) -> Stream IO Event
eventStreamAggr (handle, rootPath, cfg) = do
let recMode = getConfigRecMode cfg
flagMasks = getConfigFlag cfg
Expand All @@ -408,7 +413,7 @@ eventStreamAggr (handle, rootPath, cfg) = do
$ readDirectoryChanges rootPath handle recMode flagMasks

pathsToHandles ::
NonEmpty Path -> Config -> Stream IO (HANDLE, Path, Config)
NonEmpty FilePath -> Config -> Stream IO (HANDLE, FilePath, Config)
pathsToHandles paths cfg = do
let pathStream = S.fromList (NonEmpty.toList paths)
st2 = S.mapM getWatchHandle pathStream
Expand All @@ -420,7 +425,7 @@ pathsToHandles paths cfg = do

-- | Close a Directory handle.
--
closePathHandleStream :: Stream IO (HANDLE, Path, Config) -> IO ()
closePathHandleStream :: Stream IO (HANDLE, FilePath, Config) -> IO ()
closePathHandleStream =
let f (h, _, _) = closeHandle h
in S.fold (Fold.drainMapM f)
Expand Down Expand Up @@ -462,7 +467,10 @@ watchWith f paths =

where

before = return $ pathsToHandles paths $ f defaultConfig
before =
return
$ pathsToHandles (NonEmpty.map Path.toString paths)
$ f defaultConfig
after = closePathHandleStream

-- | Same as 'watchWith' using 'defaultConfig' and recursive mode.
Expand Down Expand Up @@ -492,14 +500,14 @@ getFlag mask Event{..} = eventFlags == mask
-- /Pre-release/
--
getRelPath :: Event -> Path
getRelPath Event{..} = eventRelPath
getRelPath Event{..} = unsafePerformIO $ Path.fromString eventRelPath

-- | Get the watch root directory to which this event belongs.
--
-- /Pre-release/
--
getRoot :: Event -> Path
getRoot Event{..} = eventRootPath
getRoot Event{..} = unsafePerformIO $ Path.fromString eventRootPath

-- | Get the absolute file system object path for which the event is generated.
--
Expand Down

0 comments on commit e0348e6

Please sign in to comment.