on master help sign in
Replace CApiFFI with ccall

CApiFFI does not seem to be working on macOS 10.15. It seems to be working on 10.12, it was compiling on nix which is using 10.12. Also, update documentation, rename overflow APIs, use NonEmpty list for paths, change the Batching timer default to 0.

commit80bcdcfcb3c38aa50fd46212dfd9c59366e97a37 authorHarendra Kumar <harendra@composewell.com> dateSat 15 Aug 2020, 06:15 (6 years ago) parentc10061b
3 files changed+302−140
src/Streamly/Internal/FileSystem/Event/Darwin.c+95 src/Streamly/Internal/FileSystem/Event/Darwin.h+45 src/Streamly/Internal/FileSystem/Event/Darwin.hs+162−140
src/Streamly/Internal/FileSystem/Event/Darwin.c+95
@@ -20,6 +20,101 @@
2020 * output end to get the events.
2121 */
2222
23+/******************************************************************************
24+ * Create Flags
25+ *****************************************************************************/
26+
27+UInt32 FSEventStreamCreateFlagNoDefer () {
28+ return kFSEventStreamCreateFlagNoDefer;
29+}
30+UInt32 FSEventStreamCreateFlagWatchRoot () {
31+ return kFSEventStreamCreateFlagWatchRoot;
32+}
33+UInt32 FSEventStreamCreateFlagFileEvents () {
34+ return kFSEventStreamCreateFlagFileEvents;
35+}
36+UInt32 FSEventStreamCreateFlagIgnoreSelf () {
37+ return kFSEventStreamCreateFlagIgnoreSelf;
38+}
39+#if 0
40+UInt32 FSEventStreamCreateFlagFullHistory = kFSEventStreamCreateFlagFullHistory;
41+#endif
42+
43+/******************************************************************************
44+ * Event Flags
45+ *****************************************************************************/
46+
47+UInt32 FSEventStreamEventFlagEventIdsWrapped () {
48+ return kFSEventStreamEventFlagEventIdsWrapped;
49+}
50+UInt32 FSEventStreamEventFlagMustScanSubDirs () {
51+ return kFSEventStreamEventFlagMustScanSubDirs;
52+}
53+UInt32 FSEventStreamEventFlagKernelDropped () {
54+ return kFSEventStreamEventFlagKernelDropped;
55+}
56+UInt32 FSEventStreamEventFlagUserDropped () {
57+ return kFSEventStreamEventFlagUserDropped;
58+}
59+UInt32 FSEventStreamEventFlagHistoryDone () {
60+ return kFSEventStreamEventFlagHistoryDone;
61+}
62+UInt32 FSEventStreamEventFlagRootChanged () {
63+ return kFSEventStreamEventFlagRootChanged;
64+}
65+UInt32 FSEventStreamEventFlagMount () {
66+ return kFSEventStreamEventFlagMount;
67+}
68+UInt32 FSEventStreamEventFlagUnmount () {
69+ return kFSEventStreamEventFlagUnmount;
70+}
71+UInt32 FSEventStreamEventFlagItemChangeOwner () {
72+ return kFSEventStreamEventFlagItemChangeOwner;
73+}
74+UInt32 FSEventStreamEventFlagItemInodeMetaMod () {
75+ return kFSEventStreamEventFlagItemInodeMetaMod;
76+}
77+UInt32 FSEventStreamEventFlagItemFinderInfoMod () {
78+ return kFSEventStreamEventFlagItemFinderInfoMod;
79+}
80+UInt32 FSEventStreamEventFlagItemXattrMod () {
81+ return kFSEventStreamEventFlagItemXattrMod;
82+}
83+UInt32 FSEventStreamEventFlagItemCreated () {
84+ return kFSEventStreamEventFlagItemCreated;
85+}
86+UInt32 FSEventStreamEventFlagItemRemoved () {
87+ return kFSEventStreamEventFlagItemRemoved;
88+}
89+UInt32 FSEventStreamEventFlagItemRenamed () {
90+ return kFSEventStreamEventFlagItemRenamed;
91+}
92+UInt32 FSEventStreamEventFlagItemModified () {
93+ return kFSEventStreamEventFlagItemModified;
94+}
95+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
96+UInt32 FSEventStreamEventFlagItemCloned () {
97+ return kFSEventStreamEventFlagItemCloned;
98+}
99+#endif
100+UInt32 FSEventStreamEventFlagItemIsDir () {
101+ return kFSEventStreamEventFlagItemIsDir;
102+}
103+UInt32 FSEventStreamEventFlagItemIsFile () {
104+ return kFSEventStreamEventFlagItemIsFile;
105+}
106+UInt32 FSEventStreamEventFlagItemIsSymlink () {
107+ return kFSEventStreamEventFlagItemIsSymlink;
108+}
109+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
110+UInt32 FSEventStreamEventFlagItemIsHardlink () {
111+ return kFSEventStreamEventFlagItemIsHardlink;
112+}
113+#endif
114+UInt32 FSEventStreamEventFlagItemIsLastHardlink () {
115+ return kFSEventStreamEventFlagItemIsLastHardlink;
116+}
117+
23118/******************************************************************************
24119 * Event watch
25120 *****************************************************************************/
src/Streamly/Internal/FileSystem/Event/Darwin.h+45
@@ -1,3 +1,5 @@
1+#include <Availability.h>
2+
13struct watch;
24
35struct pathName {
@@ -16,3 +18,46 @@ int createWatch
1618 );
1719
1820void destroyWatch(struct watch* w);
21+
22+/******************************************************************************
23+ * Create Flags
24+ *****************************************************************************/
25+
26+UInt32 FSEventStreamCreateFlagNoDefer ();
27+UInt32 FSEventStreamCreateFlagWatchRoot ();
28+UInt32 FSEventStreamCreateFlagFileEvents ();
29+UInt32 FSEventStreamCreateFlagIgnoreSelf ();
30+#if 0
31+UInt32 FSEventStreamCreateFlagFullHistory;
32+#endif
33+
34+/******************************************************************************
35+ * Event Flags
36+ *****************************************************************************/
37+
38+UInt32 FSEventStreamEventFlagEventIdsWrapped ();
39+UInt32 FSEventStreamEventFlagMustScanSubDirs ();
40+UInt32 FSEventStreamEventFlagKernelDropped ();
41+UInt32 FSEventStreamEventFlagUserDropped ();
42+UInt32 FSEventStreamEventFlagHistoryDone ();
43+UInt32 FSEventStreamEventFlagRootChanged ();
44+UInt32 FSEventStreamEventFlagMount ();
45+UInt32 FSEventStreamEventFlagUnmount ();
46+UInt32 FSEventStreamEventFlagItemChangeOwner ();
47+UInt32 FSEventStreamEventFlagItemInodeMetaMod ();
48+UInt32 FSEventStreamEventFlagItemFinderInfoMod ();
49+UInt32 FSEventStreamEventFlagItemXattrMod ();
50+UInt32 FSEventStreamEventFlagItemCreated ();
51+UInt32 FSEventStreamEventFlagItemRemoved ();
52+UInt32 FSEventStreamEventFlagItemRenamed ();
53+UInt32 FSEventStreamEventFlagItemModified ();
54+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
55+UInt32 FSEventStreamEventFlagItemCloned ();
56+#endif
57+UInt32 FSEventStreamEventFlagItemIsDir ();
58+UInt32 FSEventStreamEventFlagItemIsFile ();
59+UInt32 FSEventStreamEventFlagItemIsSymlink ();
60+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
61+UInt32 FSEventStreamEventFlagItemIsHardlink ();
62+#endif
63+UInt32 FSEventStreamEventFlagItemIsLastHardlink ();
src/Streamly/Internal/FileSystem/Event/Darwin.hs+162−140
@@ -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"