module System.Win32.FileNotify
( Handle
, Action(..)
, getWatchHandle
, readDirectoryChanges
) where
import System.Win32.File
import System.Win32.Types
import Foreign
import Foreign.C
import Data.Bits
type Handle = HANDLE
getWatchHandle :: FilePath -> IO Handle
getWatchHandle dir =
createFile dir
fILE_LIST_DIRECTORY
(fILE_SHARE_READ .|. fILE_SHARE_WRITE)
Nothing
oPEN_EXISTING
fILE_FLAG_BACKUP_SEMANTICS
Nothing
readDirectoryChanges :: Handle -> Bool -> FileNotificationFlag -> IO [(Action, String)]
readDirectoryChanges h wst mask = do
let maxBuf = 16384
allocaBytes maxBuf $ \buffer -> do
alloca $ \bret -> do
readDirectoryChangesW h buffer (toEnum maxBuf) wst mask bret
readChanges buffer
data Action = FileAdded | FileRemoved | FileModified | FileRenamedOld | FileRenamedNew
deriving (Show, Read, Eq, Ord, Enum)
readChanges :: Ptr FILE_NOTIFY_INFORMATION -> IO [(Action, String)]
readChanges pfni = do
fni <- peekFNI pfni
let entry = (faToAction $ fniAction fni, fniFileName fni)
nioff = fromEnum $ fniNextEntryOffset fni
entries <- if nioff == 0 then return [] else readChanges $ pfni `plusPtr` nioff
return $ entry:entries
faToAction :: FileAction -> Action
faToAction fa = toEnum $ fromEnum fa 1
fILE_LIST_DIRECTORY :: AccessMode
fILE_LIST_DIRECTORY = 1
type FileAction = DWORD
fILE_ACTION_ADDED :: FileAction
fILE_ACTION_ADDED = 1
fILE_ACTION_REMOVED :: FileAction
fILE_ACTION_REMOVED = 2
fILE_ACTION_MODIFIED :: FileAction
fILE_ACTION_MODIFIED = 3
fILE_ACTION_RENAMED_OLD_NAME :: FileAction
fILE_ACTION_RENAMED_OLD_NAME = 4
fILE_ACTION_RENAMED_NEW_NAME :: FileAction
fILE_ACTION_RENAMED_NEW_NAME = 5
type WCHAR = Word16
type LPOVERLAPPED_COMPLETION_ROUTINE = FunPtr ((DWORD, DWORD, LPOVERLAPPED) -> IO ())
data FILE_NOTIFY_INFORMATION = FILE_NOTIFY_INFORMATION
{ fniNextEntryOffset, fniAction :: DWORD
, fniFileName :: String
}
peekFNI :: Ptr FILE_NOTIFY_INFORMATION -> IO FILE_NOTIFY_INFORMATION
peekFNI buf = do
neof <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) buf
acti <- ((\hsc_ptr -> peekByteOff hsc_ptr 4)) buf
fnle <- ((\hsc_ptr -> peekByteOff hsc_ptr 8)) buf
fnam <- peekCWStringLen
(buf `plusPtr` ((12)),
fromEnum (fnle :: DWORD) `div` 2 )
return $ FILE_NOTIFY_INFORMATION neof acti fnam
readDirectoryChangesW :: Handle -> Ptr FILE_NOTIFY_INFORMATION -> DWORD -> BOOL -> FileNotificationFlag -> LPDWORD -> IO ()
readDirectoryChangesW h buf bufSize wst f br =
failIfFalse_ "ReadDirectoryChangesW" $ c_ReadDirectoryChangesW h (castPtr buf) bufSize wst f br nullPtr nullFunPtr
foreign import stdcall interruptible "windows.h ReadDirectoryChangesW"
c_ReadDirectoryChangesW :: Handle -> LPVOID -> DWORD -> BOOL -> DWORD
-> LPDWORD -> LPOVERLAPPED -> LPOVERLAPPED_COMPLETION_ROUTINE -> IO BOOL
fILE_NOTIFY_CHANGE_CREATION :: FileNotificationFlag
fILE_NOTIFY_CHANGE_CREATION = 64
fILE_NOTIFY_CHANGE_LAST_ACCESS :: FileNotificationFlag
fILE_NOTIFY_CHANGE_LAST_ACCESS = 32