    {-# LINE 1 "src/System/INotify.hsc" #-}
    {-# LANGUAGE CPP #-}
    -----------------------------------------------------------------------------
    -- |
    -- Module      :  System.INotify
    -- Copyright   :  (c) Lennart Kolmodin 2006-2012
    -- License     :  BSD3
    -- Maintainer  :  kolmodin@gmail.com
    -- Stability   :  experimental
    -- Portability :  hc portable, linux only
    --
    -- A Haskell binding to INotify.
    -- See <http://www.kernel.org/pub/linux/kernel/people/rml/inotify/> and @man
    -- inotify@.
    --
    -- Use 'initINotify' to get a 'INotify', then use 'addWatch' to
    -- add a watch on a file or directory. Select which events you're interested
    -- in with 'EventVariety', which corresponds to the 'Event' events.
    --
    -- Use 'removeWatch' once you don't want to watch a file any more.
    --
    -----------------------------------------------------------------------------

    module System.INotify
        ( initINotify
        , killINotify
        , withINotify
        , addWatch
        , removeWatch
        , INotify
        , WatchDescriptor
        , Event(..)
        , EventVariety(..)
        , Cookie
        ) where

    import Control.Concurrent
    import Control.Concurrent.Async
    import Control.Exception as E hiding (mask)
    import Control.Monad
    import Data.Bits ((.|.))
    import Data.Map (Map)
    import qualified Data.Map as Map
    import Data.Maybe
    import Foreign.C
    import Foreign.Marshal hiding (void)
    import Foreign.Ptr
    import Foreign.Storable
    import GHC.IO.Device (IODeviceType(Stream))
    import GHC.IO.FD as FD (mkFD)
    import GHC.IO.Handle (mkFileHandle)
    import Prelude hiding (init)
    import System.INotify.Masks
    import System.IO
    import System.IO.Error
    import System.Posix.ByteString.FilePath
    import System.Posix.Files.ByteString

    type FD = CInt
    type WD = CInt
    type Masks = CUInt

    type EventMap = Map WD (Event -> IO ())
    type WDEvent = (WD, Event)

    data INotify = INotify Handle FD (MVar EventMap) (Async ()) (Async ())
    data WatchDescriptor = WatchDescriptor INotify WD deriving WatchDescriptor -> WatchDescriptor -> Bool
    (WatchDescriptor -> WatchDescriptor -> Bool)
    -> (WatchDescriptor -> WatchDescriptor -> Bool)
    -> Eq WatchDescriptor
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: WatchDescriptor -> WatchDescriptor -> Bool
    == :: WatchDescriptor -> WatchDescriptor -> Bool
    $c/= :: WatchDescriptor -> WatchDescriptor -> Bool
    /= :: WatchDescriptor -> WatchDescriptor -> Bool
    Eq

    instance Eq INotify where
      (INotify Handle
    _ CInt
    fd1 MVar EventMap
    _ Async ()
    _ Async ()
    _) == :: INotify -> INotify -> Bool
    == (INotify Handle
    _ CInt
    fd2 MVar EventMap
    _ Async ()
    _ Async ()
    _) = CInt
    fd1 CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == CInt
    fd2

    newtype Cookie = Cookie CUInt deriving (Cookie -> Cookie -> Bool
    (Cookie -> Cookie -> Bool)
    -> (Cookie -> Cookie -> Bool) -> Eq Cookie
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Cookie -> Cookie -> Bool
    == :: Cookie -> Cookie -> Bool
    $c/= :: Cookie -> Cookie -> Bool
    /= :: Cookie -> Cookie -> Bool
    Eq,Eq Cookie
    Eq Cookie =>
    (Cookie -> Cookie -> Ordering)
    -> (Cookie -> Cookie -> Bool)
    -> (Cookie -> Cookie -> Bool)
    -> (Cookie -> Cookie -> Bool)
    -> (Cookie -> Cookie -> Bool)
    -> (Cookie -> Cookie -> Cookie)
    -> (Cookie -> Cookie -> Cookie)
    -> Ord Cookie
    Cookie -> Cookie -> Bool
    Cookie -> Cookie -> Ordering
    Cookie -> Cookie -> Cookie
    forall a.
    Eq a =>
    (a -> a -> Ordering)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> Bool)
    -> (a -> a -> a)
    -> (a -> a -> a)
    -> Ord a
    $ccompare :: Cookie -> Cookie -> Ordering
    compare :: Cookie -> Cookie -> Ordering
    $c< :: Cookie -> Cookie -> Bool
    < :: Cookie -> Cookie -> Bool
    $c<= :: Cookie -> Cookie -> Bool
    <= :: Cookie -> Cookie -> Bool
    $c> :: Cookie -> Cookie -> Bool
    > :: Cookie -> Cookie -> Bool
    $c>= :: Cookie -> Cookie -> Bool
    >= :: Cookie -> Cookie -> Bool
    $cmax :: Cookie -> Cookie -> Cookie
    max :: Cookie -> Cookie -> Cookie
    $cmin :: Cookie -> Cookie -> Cookie
    min :: Cookie -> Cookie -> Cookie
    Ord)

    data FDEvent = FDEvent WD Masks CUInt{-Cookie-} (Maybe RawFilePath) deriving (FDEvent -> FDEvent -> Bool
    (FDEvent -> FDEvent -> Bool)
    -> (FDEvent -> FDEvent -> Bool) -> Eq FDEvent
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: FDEvent -> FDEvent -> Bool
    == :: FDEvent -> FDEvent -> Bool
    $c/= :: FDEvent -> FDEvent -> Bool
    /= :: FDEvent -> FDEvent -> Bool
    Eq, Int -> FDEvent -> ShowS
    [FDEvent] -> ShowS
    FDEvent -> String
    (Int -> FDEvent -> ShowS)
    -> (FDEvent -> String) -> ([FDEvent] -> ShowS) -> Show FDEvent
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> FDEvent -> ShowS
    showsPrec :: Int -> FDEvent -> ShowS
    $cshow :: FDEvent -> String
    show :: FDEvent -> String
    $cshowList :: [FDEvent] -> ShowS
    showList :: [FDEvent] -> ShowS
    Show)

    data Event =
        -- | A file was accessed. @Accessed isDirectory file@
          Accessed
            { Event -> Bool
    isDirectory :: Bool
            , Event -> Maybe RawFilePath
    maybeFilePath :: Maybe RawFilePath
            }
        -- | A file was modified. @Modified isDirectory file@
        | Modified
            { isDirectory :: Bool
            , maybeFilePath :: Maybe RawFilePath
            }
        -- | A files attributes where changed. @Attributes isDirectory file@
        | Attributes
            { isDirectory :: Bool
            , maybeFilePath :: Maybe RawFilePath
            }
        -- | A file was closed. @Closed isDirectory file wasWriteable@
        | Closed
            { isDirectory :: Bool
            , maybeFilePath :: Maybe RawFilePath
            , Event -> Bool
    wasWriteable :: Bool
            }
        -- | A file was opened. @Opened isDirectory maybeFilePath@
        | Opened
            { isDirectory :: Bool
            , maybeFilePath :: Maybe RawFilePath
            }
        -- | A file was moved away from the watched dir. @MovedFrom isDirectory from cookie@
        | MovedOut
            { isDirectory :: Bool
            , Event -> RawFilePath
    filePath :: RawFilePath
            , Event -> Cookie
    moveCookie :: Cookie
            }
        -- | A file was moved into the watched dir. @MovedTo isDirectory to cookie@
        | MovedIn
            { isDirectory :: Bool
            , filePath :: RawFilePath
            , moveCookie :: Cookie
            }
        -- | The watched file was moved. @MovedSelf isDirectory@
        | MovedSelf
            { isDirectory :: Bool
            }
        -- | A file was created. @Created isDirectory file@
        | Created
            { isDirectory :: Bool
            , filePath :: RawFilePath
            }
        -- | A file was deleted. @Deleted isDirectory file@
        | Deleted
            { isDirectory :: Bool
            , filePath :: RawFilePath
            }
        -- | The file watched was deleted.
        | DeletedSelf
        -- | The file watched was unmounted.
        | Unmounted
        -- | The queue overflowed.
        | QOverflow
        | Ignored
        | Unknown FDEvent
        deriving (Event -> Event -> Bool
    (Event -> Event -> Bool) -> (Event -> Event -> Bool) -> Eq Event
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Event -> Event -> Bool
    == :: Event -> Event -> Bool
    $c/= :: Event -> Event -> Bool
    /= :: Event -> Event -> Bool
    Eq, Int -> Event -> ShowS
    [Event] -> ShowS
    Event -> String
    (Int -> Event -> ShowS)
    -> (Event -> String) -> ([Event] -> ShowS) -> Show Event
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Event -> ShowS
    showsPrec :: Int -> Event -> ShowS
    $cshow :: Event -> String
    show :: Event -> String
    $cshowList :: [Event] -> ShowS
    showList :: [Event] -> ShowS
    Show)

    data EventVariety
        = Access
        | Modify
        | Attrib
        | Close
        | CloseWrite
        | CloseNoWrite
        | Open
        | Move
        | MoveIn
        | MoveOut
        | MoveSelf
        | Create
        | Delete
        | DeleteSelf
        | OnlyDir
        | NoSymlink
        | MaskAdd
        | OneShot
        | AllEvents
        deriving EventVariety -> EventVariety -> Bool
    (EventVariety -> EventVariety -> Bool)
    -> (EventVariety -> EventVariety -> Bool) -> Eq EventVariety
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: EventVariety -> EventVariety -> Bool
    == :: EventVariety -> EventVariety -> Bool
    $c/= :: EventVariety -> EventVariety -> Bool
    /= :: EventVariety -> EventVariety -> Bool
    Eq

    instance Show INotify where
        show :: INotify -> String
    show (INotify Handle
    _ CInt
    fd MVar EventMap
    _ Async ()
    _ Async ()
    _) =
            String -> ShowS
    showString String
    "<inotify fd=" ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    .
            CInt -> ShowS
    forall a. Show a => a -> ShowS
    shows CInt
    fd ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $ String
    ">"

    instance Show WatchDescriptor where
        show :: WatchDescriptor -> String
    show (WatchDescriptor INotify
    _ CInt
    wd) = String -> ShowS
    showString String
    "<wd=" ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> ShowS
    forall a. Show a => a -> ShowS
    shows CInt
    wd ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $ String
    ">"

    instance Show Cookie where
        show :: Cookie -> String
    show (Cookie CUInt
    c) = String -> ShowS
    showString String
    "<cookie " ShowS -> ShowS -> ShowS
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CUInt -> ShowS
    forall a. Show a => a -> ShowS
    shows CUInt
    c ShowS -> ShowS
    forall a b. (a -> b) -> a -> b
    $ String
    ">"

    initINotify :: IO INotify
    initINotify :: IO INotify
    initINotify = do
        fdint <- String -> IO CInt -> IO CInt
    forall a. (Eq a, Num a) => String -> IO a -> IO a
    throwErrnoIfMinus1 String
    "initINotify" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ CInt -> IO CInt
    c_inotify_init1 (CInt
    c_IN_NONBLOCK CInt -> CInt -> CInt
    forall a. Bits a => a -> a -> a
    .|. CInt
    c_IN_CLOEXEC)
        (fd, _) <- FD.mkFD fdint ReadMode (Just (Stream,0,0))
            False -- is_socket
            True  -- make non-blocking.  Otherwise reading uses select(), which can fail when there are >=1024 FDs

        h <- mkFileHandle
            fd
            (showString "<inotify handle, fd=" . shows fd $ ">")
            ReadMode
            Nothing -- no encoding, so binary
            noNewlineTranslation

        em <- newMVar Map.empty
        (tid1, tid2) <- inotify_start_thread h em
        return (INotify h fdint em tid1 tid2)

    addWatch :: INotify -> [EventVariety] -> RawFilePath -> (Event -> IO ()) -> IO WatchDescriptor
    addWatch :: INotify
    -> [EventVariety]
    -> RawFilePath
    -> (Event -> IO ())
    -> IO WatchDescriptor
    addWatch inotify :: INotify
    inotify@(INotify Handle
    _ CInt
    fd MVar EventMap
    em Async ()
    _ Async ()
    _) [EventVariety]
    masks RawFilePath
    fp Event -> IO ()
    cb = do
        IO () -> (IOError -> IO ()) -> IO ()
    forall a. IO a -> (IOError -> IO a) -> IO a
    catch_IO (IO FileStatus -> IO ()
    forall (f :: * -> *) a. Functor f => f a -> f ()
    void (IO FileStatus -> IO ()) -> IO FileStatus -> IO ()
    forall a b. (a -> b) -> a -> b
    $
                  (if (EventVariety
    NoSymlink EventVariety -> [EventVariety] -> Bool
    forall a. Eq a => a -> [a] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` [EventVariety]
    masks) then RawFilePath -> IO FileStatus
    getSymbolicLinkStatus else RawFilePath -> IO FileStatus
    getFileStatus)
                  RawFilePath
    fp) ((IOError -> IO ()) -> IO ()) -> (IOError -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \IOError
    _ ->
            IOError -> IO ()
    forall a. IOError -> IO a
    ioError (IOError -> IO ()) -> IOError -> IO ()
    forall a b. (a -> b) -> a -> b
    $ IOErrorType -> String -> Maybe Handle -> Maybe String -> IOError
    mkIOError IOErrorType
    doesNotExistErrorType
                 String
    "can't watch what isn't there!"
                 Maybe Handle
    forall a. Maybe a
    Nothing
                 (String -> Maybe String
    forall a. a -> Maybe a
    Just (RawFilePath -> String
    forall a. Show a => a -> String
    show RawFilePath
    fp))
        let mask :: CUInt
    mask = [Mask] -> CUInt
    joinMasks ((EventVariety -> Mask) -> [EventVariety] -> [Mask]
    forall a b. (a -> b) -> [a] -> [b]
    map EventVariety -> Mask
    eventVarietyToMask [EventVariety]
    masks)
        wd <- RawFilePath -> (CString -> IO CInt) -> IO CInt
    forall a. RawFilePath -> (CString -> IO a) -> IO a
    withFilePath RawFilePath
    fp ((CString -> IO CInt) -> IO CInt)
    -> (CString -> IO CInt) -> IO CInt
    forall a b. (a -> b) -> a -> b
    $ \CString
    fp_c ->
                String -> IO CInt -> IO CInt
    forall a. (Eq a, Num a) => String -> IO a -> IO a
    throwErrnoIfMinus1 String
    "addWatch" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
    forall a b. (a -> b) -> a -> b
    $
                  CInt -> CString -> CUInt -> IO CInt
    c_inotify_add_watch (CInt -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CInt
    fd) CString
    fp_c CUInt
    mask
        let event = \Event
    e -> IO () -> IO ()
    ignore_failure (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
                case Event
    e of
                  -- if the event is Ignored then we know for sure that
                  -- this is the last event on that WatchDescriptor
                  Event
    Ignored -> INotify -> CInt -> IO ()
    rm_watch INotify
    inotify CInt
    wd
                  Event
    _       -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
                Event -> IO ()
    cb Event
    e
        modifyMVar_ em $ \EventMap
    em' -> EventMap -> IO EventMap
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (((Event -> IO ()) -> (Event -> IO ()) -> Event -> IO ())
    -> CInt -> (Event -> IO ()) -> EventMap -> EventMap
    forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
    Map.insertWith ((IO () -> IO () -> IO ())
    -> (Event -> IO ()) -> (Event -> IO ()) -> Event -> IO ()
    forall (m :: * -> *) a1 a2 r.
    Monad m =>
    (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
    liftM2 IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    (>>)) CInt
    wd Event -> IO ()
    event EventMap
    em')
        return (WatchDescriptor inotify wd)
        where
        -- catch_IO is same as catchIOError from base >= 4.5.0.0
        catch_IO :: IO a -> (IOError -> IO a) -> IO a
        catch_IO :: forall a. IO a -> (IOError -> IO a) -> IO a
    catch_IO = IO a -> (IOError -> IO a) -> IO a
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    E.catch
        eventVarietyToMask :: EventVariety -> Mask
    eventVarietyToMask EventVariety
    ev =
            case EventVariety
    ev of
                EventVariety
    Access -> Mask
    inAccess
                EventVariety
    Modify -> Mask
    inModify
                EventVariety
    Attrib -> Mask
    inAttrib
                EventVariety
    Close -> Mask
    inClose
                EventVariety
    CloseWrite -> Mask
    inCloseWrite
                EventVariety
    CloseNoWrite -> Mask
    inCloseNowrite
                EventVariety
    Open -> Mask
    inOpen
                EventVariety
    Move -> Mask
    inMove
                EventVariety
    MoveIn -> Mask
    inMovedTo
                EventVariety
    MoveOut -> Mask
    inMovedFrom
                EventVariety
    MoveSelf -> Mask
    inMoveSelf
                EventVariety
    Create -> Mask
    inCreate
                EventVariety
    Delete -> Mask
    inDelete
                EventVariety
    DeleteSelf-> Mask
    inDeleteSelf
                EventVariety
    OnlyDir -> Mask
    inOnlydir
                EventVariety
    NoSymlink -> Mask
    inDontFollow
                EventVariety
    MaskAdd -> Mask
    inMaskAdd
                EventVariety
    OneShot -> Mask
    inOneshot
                EventVariety
    AllEvents -> Mask
    inAllEvents

        ignore_failure :: IO () -> IO ()
        ignore_failure :: IO () -> IO ()
    ignore_failure IO ()
    action = IO ()
    action IO () -> (SomeException -> IO ()) -> IO ()
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `E.catch` SomeException -> IO ()
    ignore
          where
          ignore :: SomeException -> IO ()
          ignore :: SomeException -> IO ()
    ignore SomeException
    e
    #if MIN_VERSION_async(2,2,1)
            | Just AsyncCancelled
    AsyncCancelled <- SomeException -> Maybe AsyncCancelled
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e = SomeException -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO SomeException
    e
    #else
            | Just ThreadKilled{} <- fromException e = throwIO e
    #endif
            | Bool
    otherwise = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    removeWatch :: WatchDescriptor -> IO ()
    removeWatch :: WatchDescriptor -> IO ()
    removeWatch (WatchDescriptor (INotify Handle
    _ CInt
    fd MVar EventMap
    _ Async ()
    _ Async ()
    _) CInt
    wd) = do
        _ <- String -> IO CInt -> IO CInt
    forall a. (Eq a, Num a) => String -> IO a -> IO a
    throwErrnoIfMinus1 String
    "removeWatch" (IO CInt -> IO CInt) -> IO CInt -> IO CInt
    forall a b. (a -> b) -> a -> b
    $
          CInt -> CInt -> IO CInt
    c_inotify_rm_watch (CInt -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CInt
    fd) CInt
    wd
        return ()

    rm_watch :: INotify -> WD -> IO ()
    rm_watch :: INotify -> CInt -> IO ()
    rm_watch (INotify Handle
    _ CInt
    _ MVar EventMap
    em Async ()
    _ Async ()
    _) CInt
    wd =
        MVar EventMap -> (EventMap -> IO EventMap) -> IO ()
    forall a. MVar a -> (a -> IO a) -> IO ()
    modifyMVar_ MVar EventMap
    em (EventMap -> IO EventMap
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (EventMap -> IO EventMap)
    -> (EventMap -> EventMap) -> EventMap -> IO EventMap
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . CInt -> EventMap -> EventMap
    forall k a. Ord k => k -> Map k a -> Map k a
    Map.delete CInt
    wd)

    read_events :: Handle -> IO [WDEvent]
    read_events :: Handle -> IO [WDEvent]
    read_events Handle
    h =
        let maxRead :: Int
    maxRead = Int
    16385 in
        Int -> (Ptr (ZonkAny 1) -> IO [WDEvent]) -> IO [WDEvent]
    forall a b. Int -> (Ptr a -> IO b) -> IO b
    allocaBytes Int
    maxRead ((Ptr (ZonkAny 1) -> IO [WDEvent]) -> IO [WDEvent])
    -> (Ptr (ZonkAny 1) -> IO [WDEvent]) -> IO [WDEvent]
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 1)
    buffer -> do
            _ <- Handle -> Int -> IO Bool
    hWaitForInput Handle
    h (-Int
    1)  -- wait forever
            r <- hGetBufNonBlocking h buffer maxRead
            read_events' buffer r
        where
        read_events' :: Ptr a -> Int -> IO [WDEvent]
        read_events' :: forall a. Ptr a -> Int -> IO [WDEvent]
    read_events' Ptr a
    _ Int
    r |  Int
    r Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    <= Int
    0 = [WDEvent] -> IO [WDEvent]
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return []
        read_events' Ptr a
    ptr Int
    r = do
            wd     <- ((\Ptr a
    hsc_ptr -> Ptr a -> Int -> IO CInt
    forall b. Ptr b -> Int -> IO CInt
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr a
    hsc_ptr Int
    0))     Ptr a
    ptr :: IO CInt
    {-# LINE 274 "src/System/INotify.hsc" #-}
            mask   <- ((\Ptr a
    hsc_ptr -> Ptr a -> Int -> IO CUInt
    forall b. Ptr b -> Int -> IO CUInt
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr a
    hsc_ptr Int
    4))   ptr :: IO CUInt
    {-# LINE 275 "src/System/INotify.hsc" #-}
            cookie <- ((\Ptr a
    hsc_ptr -> Ptr a -> Int -> IO CUInt
    forall b. Ptr b -> Int -> IO CUInt
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr a
    hsc_ptr Int
    8)) ptr :: IO CUInt
    {-# LINE 276 "src/System/INotify.hsc" #-}
            len    <- ((\Ptr a
    hsc_ptr -> Ptr a -> Int -> IO CUInt
    forall b. Ptr b -> Int -> IO CUInt
    forall a b. Storable a => Ptr b -> Int -> IO a
    peekByteOff Ptr a
    hsc_ptr Int
    12))    ptr :: IO CUInt
    {-# LINE 277 "src/System/INotify.hsc" #-}
            nameM  <- if len == 0
                        then return Nothing
                        else do
                            fmap Just $ peekFilePath (((\Ptr a
    hsc_ptr -> Ptr a
    hsc_ptr Ptr a -> Int -> CString
    forall a b. Ptr a -> Int -> Ptr b
    `plusPtr` Int
    16)) ptr)
    {-# LINE 281 "src/System/INotify.hsc" #-}
            let event_size = ((Int
    16)) Int -> Int -> Int
    forall a. Num a => a -> a -> a
    + (CUInt -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral CUInt
    len)
    {-# LINE 282 "src/System/INotify.hsc" #-}
                event = FDEvent -> WDEvent
    cEvent2Haskell (CInt -> CUInt -> CUInt -> Maybe RawFilePath -> FDEvent
    FDEvent CInt
    wd CUInt
    mask CUInt
    cookie Maybe RawFilePath
    nameM)
            rest <- read_events' (ptr `plusPtr` event_size) (r - event_size)
            return (event:rest)
        cEvent2Haskell :: FDEvent
                   -> WDEvent
        cEvent2Haskell :: FDEvent -> WDEvent
    cEvent2Haskell fdevent :: FDEvent
    fdevent@(FDEvent CInt
    wd CUInt
    mask CUInt
    cookie Maybe RawFilePath
    nameM)
            = (CInt
    wd, Event
    event)
            where
            event :: Event
    event
                | Mask -> Bool
    isSet Mask
    inAccess     = Bool -> Maybe RawFilePath -> Event
    Accessed Bool
    isDir Maybe RawFilePath
    nameM
                | Mask -> Bool
    isSet Mask
    inModify     = Bool -> Maybe RawFilePath -> Event
    Modified Bool
    isDir Maybe RawFilePath
    nameM
                | Mask -> Bool
    isSet Mask
    inAttrib     = Bool -> Maybe RawFilePath -> Event
    Attributes Bool
    isDir Maybe RawFilePath
    nameM
                | Mask -> Bool
    isSet Mask
    inClose      = Bool -> Maybe RawFilePath -> Bool -> Event
    Closed Bool
    isDir Maybe RawFilePath
    nameM (Mask -> Bool
    isSet Mask
    inCloseWrite)
                | Mask -> Bool
    isSet Mask
    inOpen       = Bool -> Maybe RawFilePath -> Event
    Opened Bool
    isDir Maybe RawFilePath
    nameM
                | Mask -> Bool
    isSet Mask
    inMovedFrom  = Bool -> RawFilePath -> Cookie -> Event
    MovedOut Bool
    isDir RawFilePath
    name (CUInt -> Cookie
    Cookie CUInt
    cookie)
                | Mask -> Bool
    isSet Mask
    inMovedTo    = Bool -> RawFilePath -> Cookie -> Event
    MovedIn Bool
    isDir RawFilePath
    name (CUInt -> Cookie
    Cookie CUInt
    cookie)
                | Mask -> Bool
    isSet Mask
    inMoveSelf   = Bool -> Event
    MovedSelf Bool
    isDir
                | Mask -> Bool
    isSet Mask
    inCreate     = Bool -> RawFilePath -> Event
    Created Bool
    isDir RawFilePath
    name
                | Mask -> Bool
    isSet Mask
    inDelete     = Bool -> RawFilePath -> Event
    Deleted Bool
    isDir RawFilePath
    name
                | Mask -> Bool
    isSet Mask
    inDeleteSelf = Event
    DeletedSelf
                | Mask -> Bool
    isSet Mask
    inUnmount    = Event
    Unmounted
                | Mask -> Bool
    isSet Mask
    inQOverflow  = Event
    QOverflow
                | Mask -> Bool
    isSet Mask
    inIgnored    = Event
    Ignored
                | Bool
    otherwise          = FDEvent -> Event
    Unknown FDEvent
    fdevent
            isDir :: Bool
    isDir = Mask -> Bool
    isSet Mask
    inIsdir
            isSet :: Mask -> Bool
    isSet Mask
    bits = Mask -> CUInt -> Bool
    maskIsSet Mask
    bits CUInt
    mask
            name :: RawFilePath
    name = Maybe RawFilePath -> RawFilePath
    forall a. HasCallStack => Maybe a -> a
    fromJust Maybe RawFilePath
    nameM

    inotify_start_thread :: Handle -> MVar EventMap -> IO (Async (), Async ())
    inotify_start_thread :: Handle -> MVar EventMap -> IO (Async (), Async ())
    inotify_start_thread Handle
    h MVar EventMap
    em = do
        chan_events <- IO (Chan [WDEvent])
    forall a. IO (Chan a)
    newChan
        tid1 <- async (logFailure "dispatcher" (dispatcher chan_events))
        tid2 <- async (logFailure "start_thread" (start_thread chan_events))
        return (tid1,tid2)
        where
        start_thread :: Chan [WDEvent] -> IO ()
        start_thread :: Chan [WDEvent] -> IO ()
    start_thread Chan [WDEvent]
    chan_events = do
            events <- Handle -> IO [WDEvent]
    read_events Handle
    h
            writeChan chan_events events
            start_thread chan_events
        dispatcher :: Chan [WDEvent] -> IO ()
        dispatcher :: Chan [WDEvent] -> IO ()
    dispatcher Chan [WDEvent]
    chan_events = do
            events <- Chan [WDEvent] -> IO [WDEvent]
    forall a. Chan a -> IO a
    readChan Chan [WDEvent]
    chan_events
            mapM_ runHandler events
            dispatcher chan_events
        runHandler :: WDEvent -> IO ()
        runHandler :: WDEvent -> IO ()
    runHandler (CInt
    _,  e :: Event
    e@Event
    QOverflow) = do -- send overflows to all handlers
            handlers <- MVar EventMap -> IO EventMap
    forall a. MVar a -> IO a
    readMVar MVar EventMap
    em
            mapM_ ($ e) (Map.elems handlers)
        runHandler (CInt
    wd, Event
    event) = do
            handlers <- MVar EventMap -> IO EventMap
    forall a. MVar a -> IO a
    readMVar MVar EventMap
    em
            let handlerM = CInt -> EventMap -> Maybe (Event -> IO ())
    forall k a. Ord k => k -> Map k a -> Maybe a
    Map.lookup CInt
    wd EventMap
    handlers
            case handlerM of
              Maybe (Event -> IO ())
    Nothing -> String -> IO ()
    putStrLn String
    "runHandler: couldn't find handler" -- impossible?
              Just Event -> IO ()
    handler -> Event -> IO ()
    handler Event
    event

        logFailure :: String -> IO () -> IO ()
    logFailure String
    name IO ()
    io = IO ()
    io IO () -> (SomeException -> IO ()) -> IO ()
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `E.catch` \SomeException
    e ->
           case SomeException
    e of
    #if MIN_VERSION_async(2,2,1)
             SomeException
    _ | Just AsyncCancelled
    AsyncCancelled <- SomeException -> Maybe AsyncCancelled
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    #else
             _ | Just ThreadKilled{} <- fromException e -> return ()
    #endif
               | Bool
    otherwise -> Handle -> String -> IO ()
    hPutStrLn Handle
    stderr (String
    name String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ String
    " dying: " String -> ShowS
    forall a. [a] -> [a] -> [a]
    ++ SomeException -> String
    forall a. Show a => a -> String
    show SomeException
    e)

    killINotify :: INotify -> IO ()
    killINotify :: INotify -> IO ()
    killINotify (INotify Handle
    h CInt
    _ MVar EventMap
    _ Async ()
    tid1 Async ()
    tid2) =
        do Async () -> IO ()
    forall a. Async a -> IO ()
    cancelWait Async ()
    tid1
           Async () -> IO ()
    forall a. Async a -> IO ()
    cancelWait Async ()
    tid2
           Handle -> IO ()
    hClose Handle
    h

    cancelWait :: Async a -> IO ()
    #if MIN_VERSION_async(2,1,1)
    cancelWait :: forall a. Async a -> IO ()
    cancelWait = Async a -> IO ()
    forall a. Async a -> IO ()
    cancel
    #else
    cancelWait a = do cancel a; void $ waitCatch a
    #endif

    withINotify :: (INotify -> IO a) -> IO a
    withINotify :: forall a. (INotify -> IO a) -> IO a
    withINotify = IO INotify -> (INotify -> IO ()) -> (INotify -> IO a) -> IO a
    forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
    bracket IO INotify
    initINotify INotify -> IO ()
    killINotify

    c_IN_NONBLOCK :: CInt
    c_IN_NONBLOCK :: CInt
    c_IN_NONBLOCK = CInt
    2048
    {-# LINE 365 "src/System/INotify.hsc" #-}

    c_IN_CLOEXEC :: CInt
    c_IN_CLOEXEC :: CInt
    c_IN_CLOEXEC = CInt
    524288
    {-# LINE 368 "src/System/INotify.hsc" #-}

    foreign import ccall unsafe "sys/inotify.h inotify_init1" c_inotify_init1 :: CInt -> IO CInt
    foreign import ccall unsafe "sys/inotify.h inotify_add_watch" c_inotify_add_watch :: CInt -> CString -> CUInt -> IO CInt
    foreign import ccall unsafe "sys/inotify.h inotify_rm_watch" c_inotify_rm_watch :: CInt -> CInt -> IO CInt