@@ -14,31 +14,53 @@
1414--
1515-- @
1616-- {-\# LANGUAGE MagicHash #-}
17−-- Stream.mapM_ (putStrLn . 'showEvent') $ 'watchTrees' [Array.fromString\# "path"#]
17+-- Stream.mapM_ (putStrLn . 'showEvent') $ 'watchTrees' [Array.fromCString\# "path"#]
1818-- @
1919--
20−-- 'Event' is an opaque type. Accessor functions (e.g. 'showEvent above)
20+-- 'Event' is an opaque type. Accessor functions (e.g. 'showEvent' above)
2121-- provided in this module are used to determine the attributes of the event.
2222--
23−--
2423-- =Design notes
2524--
2625-- For reference documentation see:
2726--
28−-- *
29−-- "<https://developer.apple.com/documentation/coreservices/file_system_events?language=objc Apple FS Events Reference>"
3027-- * "<https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html Apple FS Events Programming Guide>"
28+-- * "<https://developer.apple.com/documentation/coreservices/file_system_events?language=objc Apple FS Events Reference>"
3129--
3230-- We try to keep the macOS\/Linux/Windows event handling APIs and defaults
3331-- semantically and syntactically as close as possible.
3432--
33+-- =BUGS
34+--
35+-- There may be some idiosyncracies in event reporting likely due to temporal
36+-- coalescing of events by the macOS fs events implementation.
37+--
38+-- 1. Multiple events that happen in quick succession may be coalesced into a
39+-- single event with multiple event flags set. We have observed that sometimes
40+-- "Deleted", "Renamed", "Modified" events have "Created" flag also present.
41+-- For example, on macOS 10.15.1, try "touch x; rm x" or "rm x; touch
42+-- x" or "touch x; mv x y". Sometimes even just an "rm x" produces both flags.
43+-- 2. Sometimes it has been seen that the earlier events go missing and only
44+-- the latest one is reported. See 'isCreated' for one such case.
45+-- 3. When @rm -rf@ is used on the watched root directory, only one 'isDeleted'
46+-- event occurs and that is for the root. However, @rm -rf@ on a directory
47+-- inside the watch root produces 'isDeleted' events for all files.
48+--
49+-- You may have to stat the path of the event to know more information about
50+-- what might have happened. It may be a good idea to watch the behavior of
51+-- events you are handling before you can rely on it. See the individual event
52+-- APIs for some of the known issues marked with `BUGS`. Also see the "Handling
53+-- Events" section in the "Apple FS Events Programming Guide".
54+--
55+-- * "<https://stackoverflow.com/questions/18415285/osx-fseventstreameventflags-not-working-correctly Stack overflow question on event coalescing>"
56+--
3557-- =TODO
3658--
3759-- APIs for persistent event-id related functionality, to get events from
3860-- specific event-id etc are not implemented.
3961
4062-- Need a real cpp to process Availability.h
41−{-# OPTIONS_GHC -pgmP cpp -optP -Wno-unused-command-line-argument #-}
63+{-# OPTIONS_GHC -pgmP gcc -optP -E #-}
4264
4365#include <Availability.h>
4466
@@ -77,9 +99,9 @@ module Streamly.Internal.FileSystem.Event.Darwin
7799
78100 -- ** Exception Conditions
79101 , isEventIdWrapped
80− , isOverflow
81− , isOverflowKernel
82− , isOverflowUser
102+ , isMustScanSubdirs
103+ , isKernelDropped
104+ , isUserDropped
83105
84106 -- ** Root Level Events
85107 -- | Events that belong to the root path as a whole and not to specific
@@ -96,20 +118,6 @@ module Streamly.Internal.FileSystem.Event.Darwin
96118 , isXAttrsChanged
97119
98120 -- ** Item Level CRUD events
99− -- | Note: Sometimes the "Deleted", "Renamed", "Modified" events have
100− -- "Created" flag also present, this may perhaps be due to temporal
101− -- coalescing of events. Though it is not clear why different types of
102− -- events should be coalesced together. Therefore, it may be a good idea to
103− -- check the presence of other flags before "Created" and to give
104− -- precedence to those flags in such case. For example, on macOS 10.15.1,
105− -- try "touch x; rm x" or "rm x; touch x" or "touch x; mv x y". Sometimes
106− -- even just an "rm x" produces both flags.
107− --
108− -- When @rm -rf@ is used on the watched directory, only one 'isDeleted'
109− -- event occurs and that is for the watch root. However, @rm -rf@ on a
110− -- directory inside the watch root produces 'isDeleted' events for all
111− -- files.
112−
113121 , isCreated
114122 , isDeleted
115123 , isMoved
@@ -137,6 +145,7 @@ import Control.Monad (when)
137145import Control.Monad.IO.Class (liftIO)
138146import Data.Bits ((.|.), (.&.), complement)
139147import Data.Functor.Identity (runIdentity)
148+import Data.List.NonEmpty (NonEmpty)
140149import Data.Word (Word8, Word32, Word64)
141150import Foreign.C.Types (CInt(..), CDouble(..), CSize(..), CUChar(..))
142151import Foreign.Marshal.Alloc (alloca)
@@ -150,6 +159,7 @@ import Streamly.Internal.Data.Parser (Parser)
150159import Streamly.Internal.Memory.Array.Types (Array(..))
151160import System.IO (Handle, hClose)
152161
162+import qualified Data.List.NonEmpty as NonEmpty
153163import qualified Streamly.Internal.Data.Parser as PR
154164import qualified Streamly.Internal.Data.Stream.IsStream as S
155165import qualified Streamly.Internal.Data.Unicode.Stream as U
@@ -174,8 +184,8 @@ data Config = Config
174184-- Batching Events
175185-------------------------------------------------------------------------------
176186
177−foreign import capi
178− "CoreServices/CoreServices.h value kFSEventStreamCreateFlagNoDefer"
187+foreign import ccall safe
188+ "FileSystem/Event/Darwin.h FSEventStreamCreateFlagNoDefer"
179189 kFSEventStreamCreateFlagNoDefer :: Word32
180190
181191data BatchInfo =
@@ -188,7 +198,7 @@ data BatchInfo =
188198-- | Set how the events should be batched. See 'BatchInfo' for details. A
189199-- negative value for time is treated as 0.
190200--
191−-- /default: Batch 0.1/
201+-- /default: Batch 0.0/
192202--
193203-- /macOS 10.5+/
194204--
@@ -222,12 +232,13 @@ setFlag mask status cfg@Config{..} =
222232 Off -> createFlags .&. complement mask
223233 in cfg {createFlags = flags}
224234
225−foreign import capi
226− "CoreServices/CoreServices.h value kFSEventStreamCreateFlagWatchRoot"
235+foreign import ccall safe
236+ "CoreServices/CoreServices.h FSEventStreamCreateFlagWatchRoot"
227237 kFSEventStreamCreateFlagWatchRoot :: Word32
228238
229239-- | Watch the changes to the path of the top level file system objects being
230−-- watched.
240+-- watched. If the root directory is deleted, moved or renamed you will receive
241+-- an 'isRootChanged' event with an eventId 0.
231242--
232243-- /default: Off/
233244--
@@ -238,8 +249,8 @@ foreign import capi
238249setRootChanged :: Toggle -> Config -> Config
239250setRootChanged = setFlag kFSEventStreamCreateFlagWatchRoot
240251
241−foreign import capi
242− "CoreServices/CoreServices.h value kFSEventStreamCreateFlagFileEvents"
252+foreign import ccall safe
253+ "CoreServices/CoreServices.h FSEventStreamCreateFlagFileEvents"
243254 kFSEventStreamCreateFlagFileEvents :: Word32
244255
245256-- | When this is 'Off' only events for the watched directories are reported.
@@ -260,8 +271,8 @@ foreign import capi
260271setFileEvents :: Toggle -> Config -> Config
261272setFileEvents = setFlag kFSEventStreamCreateFlagFileEvents
262273
263−foreign import capi
264− "CoreServices/CoreServices.h value kFSEventStreamCreateFlagIgnoreSelf"
274+foreign import ccall safe
275+ "CoreServices/CoreServices.h FSEventStreamCreateFlagIgnoreSelf"
265276 kFSEventStreamCreateFlagIgnoreSelf :: Word32
266277
267278-- | When this is 'On' events generated by the current process are not
@@ -277,8 +288,8 @@ setIgnoreSelf :: Toggle -> Config -> Config
277288setIgnoreSelf = setFlag kFSEventStreamCreateFlagIgnoreSelf
278289
279290#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500
280−foreign import capi
281− "CoreServices/CoreServices.h value kFSEventStreamCreateFlagFullHistory"
291+foreign import ccall safe
292+ "CoreServices/CoreServices.h FSEventStreamCreateFlagFullHistory"
282293 kFSEventStreamCreateFlagFullHistory :: Word32
283294
284295-- | When this is 'On' all events since the beginning of time are reported.
@@ -299,7 +310,7 @@ setFullHistory = setFlag kFSEventStreamCreateFlagFullHistory
299310
300311-- | The default settings are:
301312--
302−-- * 'setEventBatching' ('Batch' 0.1)
313+-- * 'setEventBatching' ('Batch' 0.0)
303314-- * 'setFileEvents' 'On'
304315-- * 'setRootChanged' 'Off'
305316-- * 'setIgnoreSelf' 'Off'
@@ -311,7 +322,7 @@ setFullHistory = setFlag kFSEventStreamCreateFlagFullHistory
311322--
312323defaultConfig :: Config
313324defaultConfig = setFileEvents On $ Config
314− { latency = 0.1
325+ { latency = 0.0
315326 , createFlags = 0
316327 }
317328
@@ -372,12 +383,16 @@ data Watch = Watch Handle (Ptr CWatch) (MVar Bool)
372383--
373384-- /Internal/
374385--
375−openWatch :: Config -> [Array Word8] -> IO Watch
386+openWatch :: Config -> NonEmpty (Array Word8) -> IO Watch
376387openWatch Config{..} paths = do
377− withPathNames paths $ \arraysPtr ->
388+ -- XXX check whether the path exists. If the path does not exist and
389+ -- is created later it cannot be properly monitored. Also a user may
390+ -- inadvertently provide a path for which the user may not have permission
391+ -- and then later wonder why events are not being reported.
392+ withPathNames (NonEmpty.toList paths) $ \arraysPtr ->
378393 alloca $ \fdPtr -> do
379394 alloca $ \watchPPtr -> do
380− let nArrays = fromIntegral (length paths)
395+ let nArrays = fromIntegral (NonEmpty.length paths)
381396 seconds = (realToFrac latency)
382397 r <- createWatch
383398 arraysPtr nArrays createFlags 0 seconds fdPtr watchPPtr
@@ -393,7 +408,7 @@ openWatch Config{..} paths = do
393408
394409 withPathName :: Array Word8 -> (PathName -> IO a) -> IO a
395410 withPathName arr act = do
396− A.withPtr arr $ \ptr ->
411+ A.asPtr arr $ \ptr ->
397412 let pname = PathName (castPtr ptr) (fromIntegral (A.length arr))
398413 in act pname
399414
@@ -421,7 +436,7 @@ closeWatch (Watch h watchPtr mvar) = do
421436--
422437data Event = Event
423438 { eventId :: Word64
424− , eventFlags :: Word64
439+ , eventFlags :: Word32
425440 , eventAbsPath :: Array Word8
426441 } deriving (Show, Ord, Eq)
427442
@@ -441,7 +456,7 @@ readOneEvent = do
441456 path <- PR.takeEQ pathLen (A.writeN pathLen)
442457 return $ Event
443458 { eventId = eid
444− , eventFlags = eflags
459+ , eventFlags = fromIntegral eflags
445460 , eventAbsPath = path
446461 }
447462
@@ -472,21 +487,22 @@ watchToStream (Watch handle _ _) =
472487-- is deleted and recreated as a symbolic link to another path) then no events
473488-- are reported for any changes under the new path.
474489--
475−-- If a watch is started on a non-existing path then the path is not watched
476−-- even if it is created later. The macOS API does not fail for a non-existing
477−-- path. If a non-existing path is watched with 'setRootChanged' then an
478−-- 'isRootChanged' event is reported if the path is created later and the
479−-- "path" field in the event is set to the dirname of the path rather than the
480−-- full absolute path. This is the observed behavior on macOS 10.15.1.
490+-- BUGS: If a watch is started on a non-existing path then the path is not
491+-- watched even if it is created later. The macOS API does not fail for a
492+-- non-existing path. If a non-existing path is watched with 'setRootChanged'
493+-- then an 'isRootChanged' event is reported if the path is created later and
494+-- the "path" field in the event is set to the dirname of the path rather than
495+-- the full absolute path. This is the observed behavior on macOS 10.15.1.
481496--
482497-- @
483498-- {-\# LANGUAGE MagicHash #-}
484−-- watchTreesWith ('setIgnoreSelf' 'On' . 'setRootChanged' 'On') [Array.fromString\# "path"#]
499+-- watchTreesWith ('setIgnoreSelf' 'On' . 'setRootChanged' 'On') [Array.fromCString\# "path"#]
485500-- @
486501--
487502-- /Internal/
488503--
489−watchTreesWith :: (Config -> Config) -> [Array Word8] -> SerialT IO Event
504+watchTreesWith ::
505+ (Config -> Config) -> NonEmpty (Array Word8) -> SerialT IO Event
490506watchTreesWith f paths = S.bracket before after watchToStream
491507
492508 where
@@ -500,7 +516,7 @@ watchTreesWith f paths = S.bracket before after watchToStream
500516-- watchTrees = watchTreesWith id
501517-- @
502518--
503−watchTrees :: [Array Word8] -> SerialT IO Event
519+watchTrees :: NonEmpty (Array Word8) -> SerialT IO Event
504520watchTrees = watchTreesWith id
505521
506522-------------------------------------------------------------------------------
@@ -515,13 +531,14 @@ watchTrees = watchTreesWith id
515531getEventId :: Event -> Word64
516532getEventId Event{..} = eventId
517533
518−foreign import capi
519− "CoreServices/CoreServices.h value kFSEventStreamEventFlagEventIdsWrapped"
520− kFSEventStreamEventFlagEventIdsWrapped :: Word64
534+foreign import ccall safe
535+ "CoreServices/CoreServices.h FSEventStreamEventFlagEventIdsWrapped"
536+ kFSEventStreamEventFlagEventIdsWrapped :: Word32
521537
522538-- | Determine whether the event id has wrapped. This is impossible on any
523539-- traditional hardware in any reasonable amount of time unless the event-id
524540-- starts from a very high value, because the event-id is a 64-bit integer.
541+-- However, apple still recommends to check and handle this flag.
525542--
526543-- /macOS 10.5+/
527544--
@@ -542,68 +559,69 @@ getAbsPath Event{..} = eventAbsPath
542559-- Event types
543560-------------------------------------------------------------------------------
544561
545−getFlag :: Word64 -> Event -> Bool
562+getFlag :: Word32 -> Event -> Bool
546563getFlag mask Event{..} = eventFlags .&. mask /= 0
547564
548565-------------------------------------------------------------------------------
549566-- Error events
550567-------------------------------------------------------------------------------
551568
552−foreign import capi
553− "CoreServices/CoreServices.h value kFSEventStreamEventFlagMustScanSubDirs"
554− kFSEventStreamEventFlagMustScanSubDirs :: Word64
569+foreign import ccall safe
570+ "CoreServices/CoreServices.h FSEventStreamEventFlagMustScanSubDirs"
571+ kFSEventStreamEventFlagMustScanSubDirs :: Word32
555572
556−-- | Events may be dropped if the kernel or the user process is not able to
557−-- cope up with the speed, in that case multiple events from child nodes may be
558−-- coalesced into an event for the parent node thus losing some information
559−-- about where the event came from. The user application must then scan
560−-- everything under the parent node if it wants to know the current state.
573+-- | Apple documentation says that "If an event in a directory occurs at about
574+-- the same time as one or more events in a subdirectory of that directory, the
575+-- events may be coalesced into a single event." In that case you will recieve
576+-- 'isMustScanSubdirs' event. In that case the path listed in the event is
577+-- invalidated and you must rescan it to know the current state.
561578--
562−-- The event path in such case points to the highest common path under which
563−-- the events were coaleseced together.
579+-- This event can also occur if a communication error (overflow) occurs in
580+-- sending the event and the event gets dropped. In that case 'isKernelDropped'
581+-- and/or 'isUserDropped' attributes will also be set.
564582--
565583-- /macOS 10.5+/
566584--
567585-- /Internal/
568586--
569−isOverflow :: Event -> Bool
570−isOverflow = getFlag kFSEventStreamEventFlagMustScanSubDirs
587+isMustScanSubdirs :: Event -> Bool
588+isMustScanSubdirs = getFlag kFSEventStreamEventFlagMustScanSubDirs
571589
572−foreign import capi
573− "CoreServices/CoreServices.h value kFSEventStreamEventFlagKernelDropped"
574− kFSEventStreamEventFlagKernelDropped :: Word64
590+foreign import ccall safe
591+ "CoreServices/CoreServices.h FSEventStreamEventFlagKernelDropped"
592+ kFSEventStreamEventFlagKernelDropped :: Word32
575593
576−-- | Did an overflow occur due to a kernel processing issue? Set only if an
577−-- overflow occurred.
594+-- | Did an event get dropped due to a kernel processing issue? Set only when
595+-- 'isMustScanSubdirs' is also true.
578596--
579597-- /macOS 10.5+/
580598--
581599-- /Internal/
582600--
583−isOverflowKernel :: Event -> Bool
584−isOverflowKernel = getFlag kFSEventStreamEventFlagKernelDropped
601+isKernelDropped :: Event -> Bool
602+isKernelDropped = getFlag kFSEventStreamEventFlagKernelDropped
585603
586−foreign import capi
587− "CoreServices/CoreServices.h value kFSEventStreamEventFlagUserDropped"
588− kFSEventStreamEventFlagUserDropped :: Word64
604+foreign import ccall safe
605+ "CoreServices/CoreServices.h FSEventStreamEventFlagUserDropped"
606+ kFSEventStreamEventFlagUserDropped :: Word32
589607
590−-- | Did an overflow occur due to a user process issue? Set only if an overflow
591−-- occurred.
608+-- | Did an event get dropped due to a user process issue? Set only when
609+-- 'isMustScanSubdirs' is also true.
592610--
593611-- /macOS 10.5+/
594612--
595613-- /Internal/
596614--
597−isOverflowUser :: Event -> Bool
598−isOverflowUser = getFlag kFSEventStreamEventFlagUserDropped
615+isUserDropped :: Event -> Bool
616+isUserDropped = getFlag kFSEventStreamEventFlagUserDropped
599617
600618-------------------------------------------------------------------------------
601619-- Global Sentinel Events
602620-------------------------------------------------------------------------------
603621
604−foreign import capi
605− "CoreServices/CoreServices.h value kFSEventStreamEventFlagHistoryDone"
606− kFSEventStreamEventFlagHistoryDone :: Word64
622+foreign import ccall safe
623+ "CoreServices/CoreServices.h FSEventStreamEventFlagHistoryDone"
624+ kFSEventStreamEventFlagHistoryDone :: Word32
607625
608626-- | Determine whether the event is a history done marker event. A history done
609627-- event is generated when the historical events from before the current time
@@ -621,9 +639,9 @@ isHistoryDone = getFlag kFSEventStreamEventFlagHistoryDone
621639-- Events affecting the watched path only
622640-------------------------------------------------------------------------------
623641
624−foreign import capi
625− "CoreServices/CoreServices.h value kFSEventStreamEventFlagRootChanged"
626− kFSEventStreamEventFlagRootChanged :: Word64
642+foreign import ccall safe
643+ "CoreServices/CoreServices.h FSEventStreamEventFlagRootChanged"
644+ kFSEventStreamEventFlagRootChanged :: Word32
627645
628646-- | Determine whether the event indicates a change of path of the monitored
629647-- object itself. Note that the object may become unreachable or deleted after
@@ -644,9 +662,9 @@ isRootChanged = getFlag kFSEventStreamEventFlagRootChanged
644662-- Global events under the watched path
645663-------------------------------------------------------------------------------
646664
647−foreign import capi
648− "CoreServices/CoreServices.h value kFSEventStreamEventFlagMount"
649− kFSEventStreamEventFlagMount :: Word64
665+foreign import ccall safe
666+ "CoreServices/CoreServices.h FSEventStreamEventFlagMount"
667+ kFSEventStreamEventFlagMount :: Word32
650668
651669-- | Determine whether the event is a mount event. A mount event is generated
652670-- if a volume is mounted under the path being watched.
@@ -658,9 +676,9 @@ foreign import capi
658676isMount :: Event -> Bool
659677isMount = getFlag kFSEventStreamEventFlagMount
660678
661−foreign import capi
662− "CoreServices/CoreServices.h value kFSEventStreamEventFlagUnmount"
663− kFSEventStreamEventFlagUnmount :: Word64
679+foreign import ccall safe
680+ "CoreServices/CoreServices.h FSEventStreamEventFlagUnmount"
681+ kFSEventStreamEventFlagUnmount :: Word32
664682
665683-- | Determine whether the event is an unmount event. An unmount event is
666684-- generated if a volume mounted under the path being watched is unmounted.
@@ -676,9 +694,9 @@ isUnmount = getFlag kFSEventStreamEventFlagUnmount
676694-- Metadata change Events (applicable only when 'setFileEvents' is 'On')
677695-------------------------------------------------------------------------------
678696
679−foreign import capi
680− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemChangeOwner"
681− kFSEventStreamEventFlagItemChangeOwner :: Word64
697+foreign import ccall safe
698+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemChangeOwner"
699+ kFSEventStreamEventFlagItemChangeOwner :: Word32
682700
683701-- | Determine whether the event is ownership, group, permissions or ACL change
684702-- event of an object contained within the monitored path.
@@ -697,9 +715,9 @@ foreign import capi
697715isOwnerGroupModeChanged :: Event -> Bool
698716isOwnerGroupModeChanged = getFlag kFSEventStreamEventFlagItemChangeOwner
699717
700−foreign import capi
701− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemInodeMetaMod"
702− kFSEventStreamEventFlagItemInodeMetaMod :: Word64
718+foreign import ccall safe
719+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemInodeMetaMod"
720+ kFSEventStreamEventFlagItemInodeMetaMod :: Word32
703721
704722-- | Determine whether the event indicates inode metadata change for an object
705723-- contained within the monitored path. This event is generated when inode
@@ -718,9 +736,9 @@ foreign import capi
718736isInodeAttrsChanged :: Event -> Bool
719737isInodeAttrsChanged = getFlag kFSEventStreamEventFlagItemInodeMetaMod
720738
721−foreign import capi
722− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemFinderInfoMod"
723− kFSEventStreamEventFlagItemFinderInfoMod :: Word64
739+foreign import ccall safe
740+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemFinderInfoMod"
741+ kFSEventStreamEventFlagItemFinderInfoMod :: Word32
724742
725743-- | Determine whether the event indicates finder information metadata change
726744-- for an object contained within the monitored path.
@@ -734,9 +752,9 @@ foreign import capi
734752isFinderInfoChanged :: Event -> Bool
735753isFinderInfoChanged = getFlag kFSEventStreamEventFlagItemFinderInfoMod
736754
737−foreign import capi
738− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemXattrMod"
739− kFSEventStreamEventFlagItemXattrMod :: Word64
755+foreign import ccall safe
756+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemXattrMod"
757+ kFSEventStreamEventFlagItemXattrMod :: Word32
740758
741759-- | Determine whether the event indicates extended attributes metadata change
742760-- for an object contained within the monitored path.
@@ -756,9 +774,9 @@ isXAttrsChanged = getFlag kFSEventStreamEventFlagItemXattrMod
756774-- CRUD Events (applicable only when 'setFileEvents' is 'On')
757775-------------------------------------------------------------------------------
758776
759−foreign import capi
760− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemCreated"
761− kFSEventStreamEventFlagItemCreated :: Word64
777+foreign import ccall safe
778+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemCreated"
779+ kFSEventStreamEventFlagItemCreated :: Word32
762780
763781-- | Determine whether the event indicates creation of an object within the
764782-- monitored path. This event is generated when any file system object other
@@ -768,9 +786,13 @@ foreign import capi
768786--
769787-- This event can occur for the watched path if the path was deleted/moved and
770788-- created again (tested on macOS 10.15.1). However, if a watch is started on a
771−-- non-existing path and the path is created later, then the this event is not
789+-- non-existing path and the path is created later, then this event is not
772790-- generated, the path is not watched.
773791--
792+-- BUGS: When we use a "touch x" to create a file for the first time only an
793+-- 'isInodeAttrsChanged' event occurs and there is no 'isCreated' event (tested
794+-- on 10.15.1).
795+--
774796-- /Applicable only when 'setFileEvents' is 'On'/
775797--
776798-- /Can occur for watched path or a file inside it/
@@ -782,9 +804,9 @@ foreign import capi
782804isCreated :: Event -> Bool
783805isCreated = getFlag kFSEventStreamEventFlagItemCreated
784806
785−foreign import capi
786− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemRemoved"
787− kFSEventStreamEventFlagItemRemoved :: Word64
807+foreign import ccall safe
808+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemRemoved"
809+ kFSEventStreamEventFlagItemRemoved :: Word32
788810
789811-- | Determine whether the event indicates deletion of an object within the
790812-- monitored path. This is true when a file or a hardlink is deleted.
@@ -800,9 +822,9 @@ foreign import capi
800822isDeleted :: Event -> Bool
801823isDeleted = getFlag kFSEventStreamEventFlagItemRemoved
802824
803−foreign import capi
804− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemRenamed"
805− kFSEventStreamEventFlagItemRenamed :: Word64
825+foreign import ccall safe
826+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemRenamed"
827+ kFSEventStreamEventFlagItemRenamed :: Word32
806828
807829-- | Determine whether the event indicates rename of an object within the
808830-- monitored path. This event is generated when a file is renamed within the
@@ -819,9 +841,9 @@ foreign import capi
819841isMoved :: Event -> Bool
820842isMoved = getFlag kFSEventStreamEventFlagItemRenamed
821843
822−foreign import capi
823− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemModified"
824− kFSEventStreamEventFlagItemModified :: Word64
844+foreign import ccall safe
845+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemModified"
846+ kFSEventStreamEventFlagItemModified :: Word32
825847
826848-- | Determine whether the event indicates modification of an object within the
827849-- monitored path. This event is generated only for files and not directories.
@@ -836,9 +858,9 @@ isModified :: Event -> Bool
836858isModified = getFlag kFSEventStreamEventFlagItemModified
837859
838860#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
839−foreign import capi
840− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemCloned"
841− kFSEventStreamEventFlagItemCloned :: Word64
861+foreign import ccall safe
862+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemCloned"
863+ kFSEventStreamEventFlagItemCloned :: Word32
842864
843865-- | Determine whether the event indicates cloning of an object within the
844866-- monitored path.
@@ -857,9 +879,9 @@ isCloned = getFlag kFSEventStreamEventFlagItemCloned
857879-- Information about path type (applicable only when 'setFileEvents' is 'On')
858880-------------------------------------------------------------------------------
859881
860−foreign import capi
861− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemIsDir"
862− kFSEventStreamEventFlagItemIsDir :: Word64
882+foreign import ccall safe
883+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemIsDir"
884+ kFSEventStreamEventFlagItemIsDir :: Word32
863885
864886-- | Determine whether the event is for a directory path.
865887--
@@ -872,9 +894,9 @@ foreign import capi
872894isDir :: Event -> Bool
873895isDir = getFlag kFSEventStreamEventFlagItemIsDir
874896
875−foreign import capi
876− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemIsFile"
877− kFSEventStreamEventFlagItemIsFile :: Word64
897+foreign import ccall safe
898+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemIsFile"
899+ kFSEventStreamEventFlagItemIsFile :: Word32
878900
879901-- | Determine whether the event is for a file path.
880902--
@@ -887,9 +909,9 @@ foreign import capi
887909isFile :: Event -> Bool
888910isFile = getFlag kFSEventStreamEventFlagItemIsFile
889911
890−foreign import capi
891− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemIsSymlink"
892− kFSEventStreamEventFlagItemIsSymlink :: Word64
912+foreign import ccall safe
913+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemIsSymlink"
914+ kFSEventStreamEventFlagItemIsSymlink :: Word32
893915
894916-- | Determine whether the event is for a symbolic link path.
895917--
@@ -903,9 +925,9 @@ isSymLink :: Event -> Bool
903925isSymLink = getFlag kFSEventStreamEventFlagItemIsSymlink
904926
905927#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
906−foreign import capi
907− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemIsHardlink"
908− kFSEventStreamEventFlagItemIsHardlink :: Word64
928+foreign import ccall safe
929+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemIsHardlink"
930+ kFSEventStreamEventFlagItemIsHardlink :: Word32
909931
910932-- | Determine whether the event is for a file with more than one hard link.
911933-- When 'isFile' is true we can check for 'isHardLink'. Note that 'isHardLink'
@@ -922,9 +944,9 @@ foreign import capi
922944isHardLink :: Event -> Bool
923945isHardLink = getFlag kFSEventStreamEventFlagItemIsHardlink
924946
925−foreign import capi
926− "CoreServices/CoreServices.h value kFSEventStreamEventFlagItemIsLastHardlink"
927− kFSEventStreamEventFlagItemIsLastHardlink :: Word64
947+foreign import ccall safe
948+ "CoreServices/CoreServices.h FSEventStreamEventFlagItemIsLastHardlink"
949+ kFSEventStreamEventFlagItemIsLastHardlink :: Word32
928950
929951-- | Determine whether the event is for a hard link path with only one hard
930952-- link. If 'isHardLink' is true then we can check for 'isLastHardLink'. This
@@ -954,9 +976,9 @@ showEvent ev@Event{..} =
954976 ++ "\nPath = " ++ show path
955977 ++ "\nFlags " ++ show eventFlags
956978
957− ++ showev isOverflow "Overflow"
958− ++ showev isOverflowKernel "OverflowKernel"
959− ++ showev isOverflowUser "OverflowUser"
979+ ++ showev isMustScanSubdirs "MustScanSubdirs"
980+ ++ showev isKernelDropped "KernelDropped"
981+ ++ showev isUserDropped "UserDropped"
960982
961983 ++ showev isRootChanged "RootChanged"
962984 ++ showev isMount "Mount"